Files
everyinc__compound-engineer…/tests/omp-native-install.test.ts
Kaitian Xie 8bf0cb1a91 feat(omp): add native oh-my-pi harness support
- detect omp (~/.omp, project .omp/) so `--to all` reports it as a
  native plugin install instead of attempting conversion; no --to omp
  converter, writer, or manifest (per CONCEPTS.md native-plugin-surface)
- docs/specs/omp.md target spec verified against omp 17.2.7; README
  gains omp install/local-dev/limitations coverage
- skills: omp built-in `ask` in blocking-question lists, `task` in
  closed subagent enumerations, and `/skill:<name>` user-facing
  invocation form across the rendering-rule copies, AGENTS.md, and the
  authoring guide
- ce-compound session history: discover omp sessions under
  ~/.omp/agent/sessions and named-profile roots (honoring
  PI_CODING_AGENT_SESSION_DIR/PI_CODING_AGENT_DIR/PI_CONFIG_DIR), detect
  omp JSONL via its physical title-slot line before the pi-shaped
  header, and reuse pi extraction for omp platform identity
- tests: detection, --to all note, session fixture + discovery/extract
  coverage, invocation-rendering parity, and a guarded
  omp-native-install smoke test

Closes #1224
2026-08-05 01:11:26 +08:00

77 lines
3.3 KiB
TypeScript

import { describe, expect, setDefaultTimeout, test } from "bun:test"
import { readdirSync, readFileSync } from "node:fs"
import path from "node:path"
import { parseFrontmatter } from "../src/utils/frontmatter"
// Smoke test for native oh-my-pi (omp) install of this repository (#1224).
// omp loads the repo directly from package.json#pi — no converter, no writer.
// Dry-run only: this file never installs into the user's real HOME.
setDefaultTimeout(20_000)
const REPO_ROOT = path.join(import.meta.dir, "..")
// Probed at module load (not beforeAll) because test.skipIf evaluates its
// condition at registration time, matching the convention in the
// *-writer.test.ts suites.
const OMP_BIN = Bun.which("omp")
const packageJson = JSON.parse(readFileSync(path.join(REPO_ROOT, "package.json"), "utf8")) as {
name: string
version: string
pi?: { extensions?: string[]; skills?: string[]; version?: string }
}
describe("omp native install", () => {
test.skipIf(OMP_BIN === null)("omp dry-run install recognizes the repository", async () => {
const proc = Bun.spawn([OMP_BIN!, "install", "--dry-run", "--json", REPO_ROOT], {
stdout: "pipe",
stderr: "pipe",
})
const [stdout, stderr, exitCode] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited,
])
expect(exitCode, `omp install --dry-run failed:\n${stderr}`).toBe(0)
const result = JSON.parse(stdout) as {
name: string
manifest: { extensions?: string[]; skills?: string[]; version?: string }
}
expect(result.name).toBe("compound-engineering")
expect(result.manifest.skills).toContain("./skills")
expect(result.manifest.extensions).toContain("./.pi/extensions/compound-engineering.ts")
// The pi manifest does not pin its own version; omp then reports the
// package.json top-level version. Read both so the test drifts with the
// repo instead of pinning a literal.
const expectedVersion = packageJson.pi?.version ?? packageJson.version
expect(result.manifest.version).toBe(expectedVersion)
})
// The dry-run JSON above does not enumerate discovered skills, so inventory
// coverage is asserted on disk instead: omp requires a frontmatter
// description for native-provider skill discovery and silently drops skills
// without one. This test spawns nothing and stays unguarded so CI hosts
// without omp still gate the inventory.
test("omp discovers the full skill inventory", () => {
const skillsDir = path.join(REPO_ROOT, "skills")
const skillDirs = readdirSync(skillsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => entry.name)
expect(skillDirs.length).toBeGreaterThan(0)
for (const dir of skillDirs) {
const skillMdPath = path.join(skillsDir, dir, "SKILL.md")
const { data } = parseFrontmatter(readFileSync(skillMdPath, "utf8"), skillMdPath)
expect(
typeof data.name === "string" && data.name.trim() !== "",
`${dir}/SKILL.md must declare a non-empty frontmatter name`,
).toBe(true)
expect(
typeof data.description === "string" && data.description.trim() !== "",
`${dir}/SKILL.md must declare a non-empty frontmatter description; omp drops skills without one`,
).toBe(true)
}
})
})