(pluginRoot, manifest)
| 124 | } |
| 125 | |
| 126 | export async function computePluginBudget(pluginRoot, manifest) { |
| 127 | const manifestPath = path.join(pluginRoot, ".codex-plugin", "plugin.json"); |
| 128 | const manifestContent = await readText(manifestPath); |
| 129 | const skillDirs = manifest?.skills |
| 130 | ? await discoverSkillDirs(pluginRoot, manifest.skills) |
| 131 | : await discoverSkillDirs(pluginRoot, "./skills/"); |
| 132 | |
| 133 | const triggerComponents = [ |
| 134 | createComponent( |
| 135 | "plugin-description", |
| 136 | manifestPath, |
| 137 | estimateTokenCount(manifest?.description || ""), |
| 138 | "Plugin marketplace summary", |
| 139 | ), |
| 140 | createComponent( |
| 141 | "default-prompts", |
| 142 | manifestPath, |
| 143 | estimateTokenCount((manifest?.interface?.defaultPrompt || []).join("\n")), |
| 144 | "Starter prompts visible in the UI", |
| 145 | ), |
| 146 | ]; |
| 147 | |
| 148 | const invokeComponents = [ |
| 149 | createComponent("plugin-manifest", manifestPath, estimateTokenCount(manifestContent), "Manifest load cost"), |
| 150 | ]; |
| 151 | const explicitOnlyComponents = []; |
| 152 | const implicitSkills = []; |
| 153 | const explicitOnlySkills = []; |
| 154 | |
| 155 | for (const skillDir of skillDirs) { |
| 156 | const skillPath = path.join(skillDir, "SKILL.md"); |
| 157 | if (!(await pathExists(skillPath))) { |
| 158 | continue; |
| 159 | } |
| 160 | const content = await readText(skillPath); |
| 161 | const parsed = parseFrontmatter(content); |
| 162 | const skillName = path.basename(skillDir); |
| 163 | const invocationPolicy = await readInvocationPolicy(skillDir); |
| 164 | |
| 165 | if (invocationPolicy.allowImplicitInvocation) { |
| 166 | implicitSkills.push(skillName); |
| 167 | triggerComponents.push( |
| 168 | createComponent( |
| 169 | `${skillName}-description`, |
| 170 | skillPath, |
| 171 | estimateTokenCount(parsed.data?.description || ""), |
| 172 | "Skill trigger description exposed through the plugin", |
| 173 | ), |
| 174 | ); |
| 175 | invokeComponents.push( |
| 176 | createComponent( |
| 177 | `${skillName}-skill-file`, |
| 178 | skillPath, |
| 179 | estimateTokenCount(content), |
| 180 | "Implicit skill invocation cost ceiling", |
| 181 | ), |
| 182 | ); |
| 183 | } else { |
no test coverage detected