test(omo-codex): batch 41 (4 files)
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readdir, readFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import test from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
formatLazyCodexHookStatusMessage,
|
||||
normalizeLazyCodexHookStatusLabel,
|
||||
parseLazyCodexHookStatusMessage,
|
||||
} from "../scripts/hook-status-message.mjs";
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
|
||||
const AGGREGATE_EXPECTED_LABELS = new Map([
|
||||
["hooks/hooks.json:SessionStart:0:0", "Loading Project Rules"],
|
||||
["hooks/hooks.json:SessionStart:1:0", "Recording Session Telemetry"],
|
||||
["hooks/hooks.json:UserPromptSubmit:0:0", "Loading Project Rules"],
|
||||
["hooks/hooks.json:UserPromptSubmit:1:0", "Checking Ultrawork Trigger"],
|
||||
["hooks/hooks.json:UserPromptSubmit:2:0", "Checking Ulw-Loop Steering"],
|
||||
["hooks/hooks.json:PreToolUse:0:0", "Enforcing Unlimited Goal Budget"],
|
||||
["hooks/hooks.json:PostToolUse:0:0", "Checking Comments"],
|
||||
["hooks/hooks.json:PostToolUse:0:1", "Checking LSP Diagnostics"],
|
||||
["hooks/hooks.json:PostToolUse:1:0", "Matching Project Rules"],
|
||||
["hooks/hooks.json:PostCompact:0:0", "Resetting Project Rule Cache"],
|
||||
["hooks/hooks.json:Stop:0:0", "Checking Start-Work Continuation"],
|
||||
["hooks/hooks.json:SubagentStop:0:0", "Checking Start-Work Continuation"],
|
||||
]);
|
||||
|
||||
const COMPONENT_EXPECTED_LABELS = new Map([
|
||||
["components/comment-checker/hooks/hooks.json:PostToolUse:0:0", "Checking Comments"],
|
||||
["components/lsp/hooks/hooks.json:PostToolUse:0:0", "Checking LSP Diagnostics"],
|
||||
["components/rules/hooks/hooks.json:SessionStart:0:0", "Loading Project Rules"],
|
||||
["components/rules/hooks/hooks.json:UserPromptSubmit:0:0", "Loading Project Rules"],
|
||||
["components/rules/hooks/hooks.json:PostToolUse:0:0", "Matching Project Rules"],
|
||||
["components/rules/hooks/hooks.json:PostCompact:0:0", "Resetting Project Rule Cache"],
|
||||
["components/telemetry/hooks/hooks.json:SessionStart:0:0", "Recording Session Telemetry"],
|
||||
["components/ultrawork/hooks/hooks.json:UserPromptSubmit:0:0", "Checking Ultrawork Trigger"],
|
||||
["components/ulw-loop/hooks/hooks.json:UserPromptSubmit:0:0", "Checking Ulw-Loop Steering"],
|
||||
["components/ulw-loop/hooks/hooks.json:PreToolUse:0:0", "Enforcing Unlimited Ulw-Loop Budget"],
|
||||
["components/start-work-continuation/hooks/hooks.json:Stop:0:0", "Checking Start-Work Continuation"],
|
||||
["components/start-work-continuation/hooks/hooks.json:SubagentStop:0:0", "Checking Start-Work Continuation"],
|
||||
]);
|
||||
|
||||
async function readJson(relativePath) {
|
||||
return JSON.parse(await readFile(join(root, relativePath), "utf8"));
|
||||
}
|
||||
|
||||
async function readComponentHookManifests() {
|
||||
const components = await readdir(join(root, "components"), { withFileTypes: true });
|
||||
const manifests = [];
|
||||
for (const entry of components) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const source = join("components", entry.name, "hooks", "hooks.json");
|
||||
const packageJson = await readJson(join("components", entry.name, "package.json"));
|
||||
manifests.push({ source, version: packageJson.version, hooks: await readJson(source) });
|
||||
}
|
||||
return manifests.sort((left, right) => left.source.localeCompare(right.source));
|
||||
}
|
||||
|
||||
function collectCommandHooks(hooks, source, version) {
|
||||
const commandHooks = [];
|
||||
for (const [eventName, groups] of Object.entries(hooks.hooks)) {
|
||||
groups.forEach((group, groupIndex) => {
|
||||
group.hooks.forEach((handler, handlerIndex) => {
|
||||
if (handler.type !== "command") return;
|
||||
commandHooks.push({
|
||||
id: `${source}:${eventName}:${groupIndex}:${handlerIndex}`,
|
||||
version,
|
||||
statusMessage: handler.statusMessage,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
return commandHooks;
|
||||
}
|
||||
|
||||
test("#given hook status label #when formatting #then prefixes LazyCodex with version", () => {
|
||||
// given
|
||||
const version = "0.1.0";
|
||||
const label = "Checking Comments";
|
||||
|
||||
// when
|
||||
const message = formatLazyCodexHookStatusMessage(version, label);
|
||||
|
||||
// then
|
||||
assert.equal(message, "LazyCodex(0.1.0): Checking Comments");
|
||||
});
|
||||
|
||||
test("#given loose legacy status label #when normalizing #then removes OMO wording and title-cases label", () => {
|
||||
// given
|
||||
const version = "0.1.0";
|
||||
const label = " checking OMO comments ";
|
||||
|
||||
// when
|
||||
const normalized = normalizeLazyCodexHookStatusLabel(label);
|
||||
const message = formatLazyCodexHookStatusMessage(version, label);
|
||||
|
||||
// then
|
||||
assert.equal(normalized, "Checking Comments");
|
||||
assert.equal(message, "LazyCodex(0.1.0): Checking Comments");
|
||||
});
|
||||
|
||||
test("#given aggregate comment-checker hook #when status is inspected #then it uses LazyCodex comments label", async () => {
|
||||
// given
|
||||
const aggregateVersion = (await readJson(".codex-plugin/plugin.json")).version;
|
||||
const aggregateHooks = await readJson("hooks/hooks.json");
|
||||
|
||||
// when
|
||||
const hooks = collectCommandHooks(aggregateHooks, "hooks/hooks.json", aggregateVersion);
|
||||
const commentCheckerHook = hooks.find((hook) => hook.id === "hooks/hooks.json:PostToolUse:0:0");
|
||||
|
||||
// then
|
||||
assert.equal(commentCheckerHook?.statusMessage, formatLazyCodexHookStatusMessage("0.1.0", "Checking Comments"));
|
||||
assert.doesNotMatch(JSON.stringify(aggregateHooks), /checking\s+OMO\s+comments/i);
|
||||
});
|
||||
|
||||
test("#given aggregate and component hooks #when status messages are inspected #then all use the LazyCodex formatter", async () => {
|
||||
// given
|
||||
const aggregateVersion = (await readJson(".codex-plugin/plugin.json")).version;
|
||||
const aggregateHooks = await readJson("hooks/hooks.json");
|
||||
const componentManifests = await readComponentHookManifests();
|
||||
|
||||
// when
|
||||
const commandHooks = [
|
||||
...collectCommandHooks(aggregateHooks, "hooks/hooks.json", aggregateVersion),
|
||||
...componentManifests.flatMap((manifest) => collectCommandHooks(manifest.hooks, manifest.source, manifest.version)),
|
||||
];
|
||||
const expectedLabels = new Map([...AGGREGATE_EXPECTED_LABELS, ...COMPONENT_EXPECTED_LABELS]);
|
||||
const mismatches = commandHooks
|
||||
.map((hook) => {
|
||||
const label = expectedLabels.get(hook.id);
|
||||
const expected = label === undefined ? undefined : formatLazyCodexHookStatusMessage(hook.version, label);
|
||||
const parsed = parseLazyCodexHookStatusMessage(hook.statusMessage);
|
||||
return { ...hook, expected, parsed };
|
||||
})
|
||||
.filter((hook) => hook.expected === undefined || hook.statusMessage !== hook.expected || hook.parsed === null)
|
||||
.map((hook) => `${hook.id}: expected ${hook.expected ?? "<missing expectation>"} but got ${hook.statusMessage}`);
|
||||
|
||||
// then
|
||||
assert.deepEqual(mismatches, []);
|
||||
assert.deepEqual(
|
||||
commandHooks.map((hook) => hook.id).sort(),
|
||||
[...expectedLabels.keys()].sort(),
|
||||
);
|
||||
for (const hook of commandHooks) {
|
||||
assert.doesNotMatch(hook.statusMessage, /\bOMO\b/i);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user