mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-09-19 01:09:55 +08:00
107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import { readdirSync, readFileSync, statSync } from "node:fs"
|
|
import path from "node:path"
|
|
|
|
/**
|
|
* Two shipping hosts route on a root `plugin.json` `$schema` under the Agent Plugins prefix,
|
|
* and both break this plugin when they do:
|
|
*
|
|
* - Codex >= 0.147 (openai/codex#37027, #1412) injects only the first MAX_SKILL_PROMPT_BYTES
|
|
* (8000) of each Agent Plugin SKILL.md; 26 skills exceed that.
|
|
* - oh-my-pi >= 17.3 (#1411) rejects any SKILL.md whose frontmatter has a key outside the
|
|
* Agent Skills closed set; the Claude Code keys `argument-hint` / `disable-model-invocation`
|
|
* are load-bearing, so 30 skills vanish. omp has no per-host override.
|
|
*
|
|
* So the root manifest stays schema-less unconditionally (docs/specs/agent-plugins.md); a
|
|
* strict client that needs conformance gets a separately emitted package. Independently, no
|
|
* new skill may cross Codex's byte bound, and OVER_BUDGET shrinks as skills are restructured.
|
|
*/
|
|
const CODEX_MAX_SKILL_PROMPT_BYTES = 8_000
|
|
const AGENT_PLUGINS_SCHEMA_PREFIX = "https://agent-plugins.org/schemas/"
|
|
|
|
/**
|
|
* Skills known to exceed the bound. Membership is a set on purpose: an over-budget skill is
|
|
* already truncated on Codex, so its exact size is not pinned and ordinary edits do not churn
|
|
* this list. Remove a name once its SKILL.md fits; never add one for a new skill.
|
|
*/
|
|
const OVER_BUDGET = new Set([
|
|
"ce-babysit-pr",
|
|
"ce-brainstorm",
|
|
"ce-code-review",
|
|
"ce-commit-push-pr",
|
|
"ce-compound",
|
|
"ce-compound-refresh",
|
|
"ce-debug",
|
|
"ce-doc-review",
|
|
"ce-dogfood",
|
|
"ce-explain",
|
|
"ce-handoff",
|
|
"ce-ideate",
|
|
"ce-optimize",
|
|
"ce-plan",
|
|
"ce-pov",
|
|
"ce-product-pulse",
|
|
"ce-proof",
|
|
"ce-prototype",
|
|
"ce-resolve-pr-feedback",
|
|
"ce-retune",
|
|
"ce-setup",
|
|
"ce-strategy",
|
|
"ce-sweep",
|
|
"ce-test-browser",
|
|
"ce-work",
|
|
"lfg",
|
|
])
|
|
|
|
const repoRoot = path.join(import.meta.dir, "..")
|
|
const skillsDir = path.join(repoRoot, "skills")
|
|
|
|
/** Byte size as a Windows checkout with CRLF line endings would inject it. */
|
|
function crlfByteSize(contents: string): number {
|
|
const lf = contents.replace(/\r\n/g, "\n")
|
|
return Buffer.byteLength(lf, "utf8") + (lf.match(/\n/g)?.length ?? 0)
|
|
}
|
|
|
|
function skillSizes(): Map<string, number> {
|
|
const sizes = new Map<string, number>()
|
|
for (const name of readdirSync(skillsDir)) {
|
|
const file = path.join(skillsDir, name, "SKILL.md")
|
|
if (!statSync(path.join(skillsDir, name)).isDirectory()) continue
|
|
try {
|
|
sizes.set(name, crlfByteSize(readFileSync(file, "utf8")))
|
|
} catch {
|
|
// no SKILL.md; other tests own that invariant
|
|
}
|
|
}
|
|
return sizes
|
|
}
|
|
|
|
describe("Codex skill prompt budget (#1412)", () => {
|
|
const sizes = skillSizes()
|
|
|
|
test("no skill newly exceeds Codex's 8000-byte prompt bound (CRLF-adjusted)", () => {
|
|
const violations: string[] = []
|
|
for (const [name, size] of sizes) {
|
|
if (size > CODEX_MAX_SKILL_PROMPT_BYTES && !OVER_BUDGET.has(name)) {
|
|
violations.push(`${name}: ${size} bytes > ${CODEX_MAX_SKILL_PROMPT_BYTES}`)
|
|
}
|
|
}
|
|
expect(violations).toEqual([])
|
|
})
|
|
|
|
test("OVER_BUDGET only lists skills that still exceed the bound (ratchet down)", () => {
|
|
const stale = [...OVER_BUDGET].filter(
|
|
(name) => (sizes.get(name) ?? 0) <= CODEX_MAX_SKILL_PROMPT_BYTES,
|
|
)
|
|
expect(stale).toEqual([])
|
|
})
|
|
|
|
test("root plugin.json never carries an Agent Plugins $schema", () => {
|
|
const manifest = JSON.parse(
|
|
readFileSync(path.join(repoRoot, "plugin.json"), "utf8"),
|
|
) as Record<string, unknown>
|
|
const schema = typeof manifest.$schema === "string" ? manifest.$schema : ""
|
|
expect(schema.startsWith(AGENT_PLUGINS_SCHEMA_PREFIX)).toBe(false)
|
|
})
|
|
})
|