diff --git a/.opencode/command/ponytail-help.md b/.opencode/command/ponytail-help.md new file mode 100644 index 0000000..bf186a8 --- /dev/null +++ b/.opencode/command/ponytail-help.md @@ -0,0 +1,5 @@ +--- +description: Quick reference for ponytail levels, skills, and commands +--- + +Show the ponytail quick reference. One shot, change nothing: do not switch mode, write flag files, or persist anything. Levels: /ponytail lite (build what's asked, name the lazier alternative in one line), /ponytail (full, the default ladder: YAGNI then stdlib then native then one line then minimum), /ponytail ultra (deletion before addition, challenges the requirement before building). Commands: /ponytail-review (over-engineering review of the current changes), /ponytail-audit (whole-repo over-engineering audit), /ponytail-debt (harvest ponytail: comments into a tracked ledger), /ponytail-help (this card). Deactivate with 'stop ponytail', 'normal mode', or /ponytail off; resume anytime with /ponytail. Default mode is full; change it with the PONYTAIL_DEFAULT_MODE environment variable (off|lite|full|ultra) or a config file at ~/.config/ponytail/config.json (Windows: %APPDATA%\ponytail\config.json) with {"defaultMode": "lite"}. Resolution order: env var, then config file, then full. diff --git a/commands/ponytail-help.toml b/commands/ponytail-help.toml new file mode 100644 index 0000000..20399a6 --- /dev/null +++ b/commands/ponytail-help.toml @@ -0,0 +1,2 @@ +description = "Quick reference for ponytail levels, skills, and commands" +prompt = "Show the ponytail quick reference. One shot, change nothing: do not switch mode, write flag files, or persist anything. Levels: /ponytail lite (build what's asked, name the lazier alternative in one line), /ponytail (full, the default ladder: YAGNI then stdlib then native then one line then minimum), /ponytail ultra (deletion before addition, challenges the requirement before building). Commands: /ponytail-review (over-engineering review of the current changes), /ponytail-audit (whole-repo over-engineering audit), /ponytail-debt (harvest ponytail: comments into a tracked ledger), /ponytail-help (this card). Deactivate with 'stop ponytail', 'normal mode', or /ponytail off; resume anytime with /ponytail. Default mode is full; change it with the PONYTAIL_DEFAULT_MODE environment variable (off|lite|full|ultra) or a config file at ~/.config/ponytail/config.json (Windows: %APPDATA%\\ponytail\\config.json) with {\"defaultMode\": \"lite\"}. Resolution order: env var, then config file, then full." diff --git a/tests/commands.test.js b/tests/commands.test.js new file mode 100644 index 0000000..ef47a86 --- /dev/null +++ b/tests/commands.test.js @@ -0,0 +1,39 @@ +#!/usr/bin/env node +// Every ponytail command the pi extension registers must also ship as a +// file-based command for the hosts that need one: Claude Code (commands/*.toml, +// which Gemini CLI reuses) and OpenCode (.opencode/command/*.md). /ponytail-help +// was advertised in the README and the help card but missing both files; this +// guards that drift -- a registered command with no adapter file fails here. + +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('fs'); +const path = require('path'); + +const root = path.join(__dirname, '..'); + +// pi-extension registers the canonical command set. +const piSource = fs.readFileSync(path.join(root, 'pi-extension', 'index.js'), 'utf8'); +const commands = [...piSource.matchAll(/registerCommand\(["']([\w-]+)["']/g)].map((m) => m[1]); + +test('pi registers at least the base command', () => { + assert.ok(commands.includes('ponytail'), 'expected pi to register a ponytail command'); +}); + +test('every registered command ships a Claude commands/*.toml', () => { + for (const name of commands) { + assert.ok( + fs.existsSync(path.join(root, 'commands', `${name}.toml`)), + `missing commands/${name}.toml`, + ); + } +}); + +test('every registered command ships an OpenCode .opencode/command/*.md', () => { + for (const name of commands) { + assert.ok( + fs.existsSync(path.join(root, '.opencode', 'command', `${name}.md`)), + `missing .opencode/command/${name}.md`, + ); + } +});