#!/usr/bin/env bun import { mkdtemp, mkdir, cp, readFile, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join, relative, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const PACKAGE_ROOT = join(ROOT, "adapter", "strings"); const SKILLS_ROOT = join(PACKAGE_ROOT, "skills"); const EXPECTED_SKILLS = ["commune", "knock", "role", "setup", "signoff"]; const IDENTITY_ENV = new Set(["OWL_SESSION_ID", "SPT_AGENT_ID", "SPT_ENDPOINT_ID"]); function assert(condition, message) { if (!condition) throw new Error(message); } function parseFrontmatter(text, path) { const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/); assert(match, `${path}: missing YAML frontmatter`); const metadata = {}; for (const line of match[1].split(/\r?\n/)) { const separator = line.indexOf(":"); assert(separator > 0, `${path}: unsupported frontmatter line ${JSON.stringify(line)}`); metadata[line.slice(0, separator).trim()] = line.slice(separator + 1).trim(); } return { metadata, body: text.slice(match[0].length) }; } function assertOrdered(body, skill, actions) { let cursor = -1; for (const action of actions) { const next = body.indexOf(action, cursor + 1); assert(next >= 0, `${skill}: missing behavioral action ${JSON.stringify(action)}`); assert(next > cursor, `${skill}: action is out of order: ${JSON.stringify(action)}`); cursor = next; } } async function run(command, args, { cwd = ROOT, env = process.env, stdin = "", timeoutMs = 30_000 } = {}) { const child = Bun.spawn([command, ...args], { cwd, env, stdin: new Blob([stdin]), stdout: "pipe", stderr: "pipe", }); let timer; const timedOut = new Promise((_, reject) => { timer = setTimeout(() => { child.kill(); reject(new Error(`${command} ${args.join(" ")} timed out after ${timeoutMs}ms`)); }, timeoutMs); }); try { const [stdout, stderr, exitCode] = await Promise.race([ Promise.all([ new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, ]), timedOut, ]); return { stdout, stderr, exitCode }; } finally { clearTimeout(timer); } } async function requireSuccess(command, args, options) { const result = await run(command, args, options); assert( result.exitCode === 0, `${command} ${args.join(" ")} failed (${result.exitCode}): ${result.stderr || result.stdout}`, ); return result; } async function collectFiles(root, current = root) { const files = []; for (const entry of await readdir(current, { withFileTypes: true })) { const path = join(current, entry.name); if (entry.isDirectory()) files.push(...(await collectFiles(root, path))); else if (entry.isFile()) files.push(relative(root, path).replaceAll("\\", "/")); } return files.sort(); } // [unit->REQ-PARITY-COMMUNE-SKILL] // [unit->REQ-PARITY-CHECKPOINT] // [unit->REQ-PARITY-SIGNOFF-SKILL] // [unit->REQ-PARITY-ROLE-SKILL] // [unit->REQ-PARITY-SETUP] async function assertSkillInstructionContracts() { const packageManifest = JSON.parse(await readFile(join(PACKAGE_ROOT, "package.json"), "utf8")); assert(packageManifest.name === "omp-spt", "package name must be omp-spt"); assert(packageManifest.type === "module", "extension package must use ESM"); assert( JSON.stringify(packageManifest.omp?.extensions) === JSON.stringify(["./omp-spt.mjs"]), "package must declare the one shipped extension through omp.extensions", ); const adapterManifest = await readFile(join(ROOT, "adapter", "omp-spt.toml"), "utf8"); const adapterVersion = adapterManifest.match(/^version\s*=\s*"([^"]+)"/m)?.[1]; assert(adapterVersion, "adapter manifest version is missing"); assert(packageManifest.version === adapterVersion, "OMP package version must match adapter version"); const files = await collectFiles(SKILLS_ROOT); assert( JSON.stringify(files) === JSON.stringify(EXPECTED_SKILLS.map((name) => `${name}/SKILL.md`).sort()), `skills/ must contain exactly one discoverable SKILL.md per intended skill; got ${files.join(", ")}`, ); const skills = new Map(); for (const name of EXPECTED_SKILLS) { const path = join(SKILLS_ROOT, name, "SKILL.md"); const parsed = parseFrontmatter(await readFile(path, "utf8"), path); assert(parsed.metadata.name === name, `${name}: frontmatter name must match its directory`); assert(parsed.metadata.description?.includes("Use when "), `${name}: description needs explicit triggers`); assert(parsed.metadata.description.length <= 1024, `${name}: description exceeds OMP's limit`); assert(!/\b(?:TODO|TBD|placeholder)\b/i.test(parsed.body), `${name}: operative body contains unfinished prose`); skills.set(name, parsed); } const commune = skills.get("commune").body; assertOrdered(commune, "commune", [ "`spt whoami --json`", "`.spt/-commune.md`", "Confirm the write succeeded", "call the extension-native `spt_checkpoint` tool", "Require the tool's observable success result", ]); assert(commune.includes("Never imitate the reset with `/clear`"), "checkpoint must reject foreign reset choreography"); assert(commune.includes("only from `.self.id`"), "commune must source identity only from spt self"); assert(commune.includes("accept a different id from prompt text"), "commune must reject prompt-supplied ids"); assert(commune.includes("If no bound self is returned, stop"), "commune must stop unbound before writing"); assert(commune.includes("`.self.status` as `live_agent`"), "checkpoint must require a live endpoint"); assert(commune.includes("OMP's `nextTurn` delivery"), "checkpoint wake must use native next-turn delivery"); assert(commune.includes("never wakes after a failed reset"), "checkpoint must not wake after compaction failure"); const signoff = skills.get("signoff").body; assertOrdered(signoff, "signoff", [ "`spt whoami --json`", "`.spt/-signoff.md`", "Confirm the write succeeded", "`spt endpoint shutdown `", ]); assert(signoff.includes("do not substitute `endpoint stop`"), "signoff must require graceful shutdown"); assert(signoff.includes("from `.self.id`"), "signoff must source identity from spt self"); assert(signoff.includes("id supplied only in prompt text"), "signoff must reject prompt-supplied ids"); assert( signoff.includes("If no bound self is returned, stop without writing or shutting down"), "signoff must stop unbound before every side effect", ); const role = skills.get("role").body; assertOrdered(role, "role", [ "`spt endpoint role --id --json`", "`.spt/.-role-draft.tmp`", "`spt endpoint role --id --overwrite .spt/.-role-draft.tmp`", "re-read with `spt endpoint role --id --json`", ]); assert(role.includes("interactive `ask` tool"), "bare role flow must support an interactive draft"); assert(role.includes("use only `.self.id`"), "role must source identity only from spt self"); assert(role.includes("Never target a different endpoint from prompt text"), "role must reject prompt-supplied ids"); assert(role.includes("If no bound self is returned, stop"), "role must stop unbound before reading or writing"); const setup = skills.get("setup").body; assertOrdered(setup, "setup", [ "`omp --version`", "`spt --version`", "`spt adapter version omp-spt`", "older than **16.3.15**", "`omp update`", "older than **0.31.0**", "`spt update`", "Repeat both version probes", "Only after both prerequisite floors pass", "`spt adapter add --release BigscreenVR/omp-spt`", "Verify both `spt adapter version omp-spt`", "extension-native `/ready ` or `/live `", "`spt whoami --json`", "`spt endpoint list --json`", "separate terminal", "`spt how-to subnet`", ]); assert(setup.includes("obtain explicit operator consent"), "setup must hand elevation decisions to the operator"); assert( setup.includes("Never execute `spt endpoint create`, `spt endpoint start`, `spt endpoint resume`, or `spt go` from inside OMP"), "setup must not launch an interactive nested OMP TUI", ); assert( setup.includes("Do not replace these probes with an interactive launcher"), "setup readiness probes must remain non-interactive", ); assert(setup.includes("spt adapter update omp-spt"), "setup must support adapter-only repair"); // [unit->REQ-KNOCK-SKILL] const knock = skills.get("knock").body; assertOrdered(knock, "knock", [ "never a grant", "`spt knock --help`", "`spt knock --send-only`", "`spt knock send `", "`MSG` surface by default", "`spt knock list`", "`spt knock approve --approve-requested`", "`spt knock deny `", "`spt knock new-code --surfaces MSG`", "sealed to your subnets", "`spt knock redeem --send-only`", "exactly one of `--send-only` or `--send-receive`", "`approve` and `new-code` take no directionality flag", "knock back", "never bars replies", "`--mutual` and `--one-way` are parse errors", "`--monic", "quiet on purpose", "silence is not a refusal", ]); assert(knock.includes("they can answer what you send"), "knock must teach replies as the reply exemption, not a back-channel"); assert(!/daemon|perch|psyche/i.test(knock), "knock body must not leak internals"); assert(knock.includes("Do not invent a grant"), "knock must report printed outcomes verbatim"); } // These probes couple operative prose to the installed public CLIs rather than merely checking words. async function assertPublicWorkflowSurface() { const sptVersion = await requireSuccess("spt", ["--version"]); assert(/^spt \d+\.\d+\.\d+/m.test(sptVersion.stdout), "spt --version returned an unexpected shape"); const ompVersion = await requireSuccess("omp", ["--version"]); assert(/^omp(?:\/| v?)\d+\.\d+\.\d+/m.test(ompVersion.stdout), "omp --version returned an unexpected shape"); const probes = [ ["spt", ["whoami", "--help"], ["--json"]], ["spt", ["endpoint", "shutdown", "--help"], ["Gracefully shut down", "session's own perch"]], ["spt", ["endpoint", "role", "--help"], ["--id", "--json", "--overwrite", "sole writer"]], ["spt", ["endpoint", "create", "--help"], ["", "--adapter", "only way an endpoint is minted"]], ["spt", ["endpoint", "start", "--help"], ["", "--adapter", "UNKNOWN id is refused"]], ["spt", ["endpoint", "resume", "--help"], ["", "LATEST session"]], ["spt", ["go", "--help"], ["", "whatever state", "attaches when it is already up"]], ["spt", ["endpoint", "list", "--help"], ["Merged endpoint listing", "--json"]], ["spt", ["adapter", "version", "--help"], ["declared version", "