* Add ponytail-audit skill Whole-codebase audit for over-engineering. Scans a repository and produces a ranked report of things to delete, simplify, or replace with stdlib/native equivalents. * Drop counting-by-number heuristics: remove Phase 5 (structural audit) and TODO-age heuristic per review * feat: slim ponytail-audit and add cross-platform parity Rewrite the ponytail-audit skill to ponytail-review's lean shape (35 lines, was 111): same five tags, repo-wide scope, ranked output. Drop the prescriptive phase walkthrough, sampling rules, report template, and the license frontmatter that no other skill carries. Add the adapters the skill was missing so it ships on every supported platform the way ponytail-review does: - commands/ponytail-audit.toml - .opencode/command/ponytail-audit.md - pi-extension registerCommand (+ test) - agent-portability and README entries Co-authored-by: Alexander Brandt <github@a13x.de> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Emeriko <dietrich.gebert@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
122 lines
3.8 KiB
JavaScript
122 lines
3.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
|
|
import ponytailExtension from "../index.js";
|
|
|
|
function createPiHarness() {
|
|
const events = new Map();
|
|
const commands = new Map();
|
|
const appendedEntries = [];
|
|
const sentUserMessages = [];
|
|
|
|
const pi = {
|
|
on(eventName, handler) {
|
|
events.set(eventName, handler);
|
|
},
|
|
registerCommand(name, options) {
|
|
commands.set(name, options);
|
|
},
|
|
appendEntry(customType, data) {
|
|
appendedEntries.push({ customType, data });
|
|
},
|
|
sendUserMessage(text, options) {
|
|
sentUserMessages.push({ text, options });
|
|
},
|
|
};
|
|
|
|
ponytailExtension(pi);
|
|
return { events, commands, appendedEntries, sentUserMessages };
|
|
}
|
|
|
|
function createCommandContext(overrides = {}) {
|
|
return {
|
|
isIdle: () => true,
|
|
sessionManager: { getEntries: () => [] },
|
|
ui: { notify() {} },
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function withTempConfig(fn) {
|
|
const tempConfigHome = mkdtempSync(join(tmpdir(), "ponytail-test-"));
|
|
const previousXdg = process.env.XDG_CONFIG_HOME;
|
|
process.env.XDG_CONFIG_HOME = tempConfigHome;
|
|
|
|
return Promise.resolve()
|
|
.then(fn)
|
|
.finally(() => {
|
|
if (previousXdg === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
else process.env.XDG_CONFIG_HOME = previousXdg;
|
|
rmSync(tempConfigHome, { recursive: true, force: true });
|
|
});
|
|
}
|
|
|
|
test("extension registers Ponytail commands", () => {
|
|
const { commands } = createPiHarness();
|
|
|
|
assert.deepEqual([...commands.keys()].sort(), ["ponytail", "ponytail-audit", "ponytail-help", "ponytail-review"]);
|
|
});
|
|
|
|
test("/ponytail updates session mode and injects instructions", async () => withTempConfig(async () => {
|
|
const { commands, events, appendedEntries } = createPiHarness();
|
|
const ctx = createCommandContext();
|
|
|
|
await events.get("session_start")({ reason: "startup" }, ctx);
|
|
await commands.get("ponytail").handler("ultra", ctx);
|
|
|
|
assert.deepEqual(appendedEntries.at(-1), {
|
|
customType: "ponytail-mode",
|
|
data: { mode: "ultra" },
|
|
});
|
|
|
|
const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
assert.ok(result.systemPrompt.includes("PONYTAIL MODE ACTIVE"));
|
|
assert.ok(result.systemPrompt.includes("ultra"));
|
|
}));
|
|
|
|
test("session_start restores latest persisted mode", async () => withTempConfig(async () => {
|
|
const { events } = createPiHarness();
|
|
const ctx = createCommandContext({
|
|
sessionManager: {
|
|
getEntries: () => [
|
|
{ type: "custom", customType: "ponytail-mode", data: { mode: "lite" } },
|
|
],
|
|
},
|
|
});
|
|
|
|
await events.get("session_start")({ reason: "resume" }, ctx);
|
|
const result = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
|
|
assert.ok(result.systemPrompt.includes("lite"));
|
|
}));
|
|
|
|
test("skill alias commands delegate to Pi skill commands", async () => {
|
|
const { commands, sentUserMessages } = createPiHarness();
|
|
const ctx = createCommandContext();
|
|
|
|
await commands.get("ponytail-review").handler("", ctx);
|
|
await commands.get("ponytail-audit").handler("", ctx);
|
|
await commands.get("ponytail-help").handler("", ctx);
|
|
|
|
assert.deepEqual(sentUserMessages.map((entry) => entry.text), [
|
|
"/skill:ponytail-review",
|
|
"/skill:ponytail-audit",
|
|
"/skill:ponytail-help",
|
|
]);
|
|
});
|
|
|
|
test("normal mode disables persistent instructions", async () => withTempConfig(async () => {
|
|
const { commands, events } = createPiHarness();
|
|
const ctx = createCommandContext();
|
|
|
|
await events.get("session_start")({ reason: "startup" }, ctx);
|
|
await commands.get("ponytail").handler("ultra", ctx);
|
|
await events.get("input")({ text: "normal mode", source: "interactive" }, ctx);
|
|
|
|
const disabled = await events.get("before_agent_start")({ systemPrompt: "BASE" }, ctx);
|
|
assert.equal(disabled, undefined);
|
|
}));
|