( value: unknown, sourceLabel: string, )
| 72 | } |
| 73 | |
| 74 | export function validateConfigShape( |
| 75 | value: unknown, |
| 76 | sourceLabel: string, |
| 77 | ): asserts value is PackConfig { |
| 78 | if (!value || typeof value !== "object") { |
| 79 | throw new Error(`Invalid config from ${sourceLabel}: expected a JSON object`); |
| 80 | } |
| 81 | |
| 82 | const config = value as Record<string, unknown>; |
| 83 | if (typeof config.name !== "string" || !config.name.trim()) { |
| 84 | throw new Error(`Invalid config from ${sourceLabel}: "name" is required`); |
| 85 | } |
| 86 | |
| 87 | if (typeof config.description !== "string") { |
| 88 | throw new Error( |
| 89 | `Invalid config from ${sourceLabel}: "description" must be a string`, |
| 90 | ); |
| 91 | } |
| 92 | |
| 93 | if (typeof config.version !== "string") { |
| 94 | throw new Error( |
| 95 | `Invalid config from ${sourceLabel}: "version" must be a string`, |
| 96 | ); |
| 97 | } |
| 98 | |
| 99 | if ( |
| 100 | !Array.isArray(config.prompts) || |
| 101 | !config.prompts.every((prompt) => typeof prompt === "string") |
| 102 | ) { |
| 103 | throw new Error( |
| 104 | `Invalid config from ${sourceLabel}: "prompts" must be a string array`, |
| 105 | ); |
| 106 | } |
| 107 | |
| 108 | if (!Array.isArray(config.skills)) { |
| 109 | throw new Error(`Invalid config from ${sourceLabel}: "skills" must be an array`); |
| 110 | } |
| 111 | |
| 112 | const names = new Set<string>(); |
| 113 | config.skills.forEach((skill, index) => { |
| 114 | validateSkillEntry(skill, sourceLabel, index); |
| 115 | const normalizedName = skill.name.trim().toLowerCase(); |
| 116 | if (names.has(normalizedName)) { |
| 117 | throw new Error( |
| 118 | `Invalid config from ${sourceLabel}: duplicate skill name "${skill.name}" is not allowed`, |
| 119 | ); |
| 120 | } |
| 121 | names.add(normalizedName); |
| 122 | }); |
| 123 | } |
| 124 | |
| 125 | export function loadConfig(workDir: string): PackConfig { |
| 126 | const filePath = getPackPath(workDir); |
no test coverage detected