Wave 5 Step 15. Threads --raw plumbing through all seven action
command templates and adds a shape test covering structural plumbing
plus help.md's plain-language vocabulary.
- commands/fix.md: --raw flag parsed; fix-plan rendering groups by
userActionLanguage; humanized title/description/recommendation are
rendered verbatim from the cross-referenced scan envelope.
- commands/rollback.md: terminology pass — "manifest" → "list of
changes" in user-facing copy; the file name manifest.yaml is kept
as the machine contract; --raw threaded through.
- commands/plan.md: --raw forwarded to the planner-agent's prompt;
agent now instructed to group actions by userImpactCategory and
lead with userActionLanguage; bash block added for flag parsing.
- commands/implement.md: --raw forwarded to the implementer-agent's
prompt; progress-log lines now reference the humanized titles
already present in the action plan.
- commands/cleanup.md: --raw accepted as no-op (cleanup is
file-management only, no findings prose); bash block added.
- commands/help.md: full plain-language pass — "PreToolUse" and
"frontmatter" jargon removed from user-facing copy; new
vocabulary table surfaces the humanized userImpactCategory and
userActionLanguage labels ("Configuration mistake", "Conflict",
"Wasted tokens", "Missed opportunity", "Dead config" / "Fix this
now", "Fix soon", "Fix when convenient", "Optional cleanup",
"FYI"); --raw documented as global pass-through flag.
- commands/interview.md: --raw accepted as no-op; "unused hooks"
question phrased as "unused automation that runs at specific
events" in user-facing copy.
tests/commands/action-commands-shape.test.mjs (new, +6 tests, 780 → 786):
- structural: bash block + Read tool + --raw/$ARGUMENTS plumbing
across all 7 files
- help.md vocabulary: ≥3 userImpactCategory labels and ≥3
userActionLanguage phrases present
- help.md jargon: no bare "PreToolUse" or "frontmatter" in copy
89 lines
3.9 KiB
JavaScript
89 lines
3.9 KiB
JavaScript
/**
|
|
* Wave 5 Step 15 — Action-command-template shape tests.
|
|
*
|
|
* Verifies that the 7 action command templates have the correct structural
|
|
* shape after the humanizer integration:
|
|
*
|
|
* - All 7 files: contain a Bash invocation block, reference the Read tool,
|
|
* and contain the `--raw` flag (or the literal `"$ARGUMENTS"` string) so
|
|
* `--raw` plumbing is uniform across the toolchain.
|
|
*
|
|
* - help.md additionally: removes the most obviously technical jargon
|
|
* ("PreToolUse" / "frontmatter" mentions in the user-facing prose) and
|
|
* introduces a plain-language vocabulary table referencing the
|
|
* humanized userImpactCategory and userActionLanguage labels.
|
|
*/
|
|
|
|
import { test } from 'node:test';
|
|
import { strict as assert } from 'node:assert';
|
|
import { readFile } from 'node:fs/promises';
|
|
import { resolve, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const COMMANDS_DIR = resolve(__dirname, '..', '..', 'commands');
|
|
|
|
const ACTION_FILES = [
|
|
'fix.md',
|
|
'rollback.md',
|
|
'plan.md',
|
|
'implement.md',
|
|
'cleanup.md',
|
|
'help.md',
|
|
'interview.md',
|
|
];
|
|
|
|
const RAW_OR_ARGUMENTS_REGEX = /--raw|"\$ARGUMENTS"/;
|
|
const BASH_BLOCK_REGEX = /```bash\b/;
|
|
const READ_TOOL_REGEX = /\bRead\s+tool\b|allowed-tools:.*\bRead\b/;
|
|
|
|
async function readCommand(name) {
|
|
return await readFile(resolve(COMMANDS_DIR, name), 'utf-8');
|
|
}
|
|
|
|
test('Action: every file contains a Bash invocation block', async () => {
|
|
for (const name of ACTION_FILES) {
|
|
const content = await readCommand(name);
|
|
assert.match(content, BASH_BLOCK_REGEX, `${name} missing bash block`);
|
|
}
|
|
});
|
|
|
|
test('Action: every file references the Read tool', async () => {
|
|
for (const name of ACTION_FILES) {
|
|
const content = await readCommand(name);
|
|
assert.match(content, READ_TOOL_REGEX, `${name} missing Read tool reference`);
|
|
}
|
|
});
|
|
|
|
test('Action: every file contains --raw or "$ARGUMENTS" (pass-through plumbing)', async () => {
|
|
for (const name of ACTION_FILES) {
|
|
const content = await readCommand(name);
|
|
assert.match(content, RAW_OR_ARGUMENTS_REGEX, `${name} missing --raw / $ARGUMENTS plumbing`);
|
|
}
|
|
});
|
|
|
|
test('help.md: introduces plain-language vocabulary referencing humanized categories', async () => {
|
|
const content = await readCommand('help.md');
|
|
// At least three of the userImpactCategory labels should appear
|
|
const labels = ['Configuration mistake', 'Conflict', 'Wasted tokens', 'Missed opportunity', 'Dead config'];
|
|
const present = labels.filter(l => content.includes(l));
|
|
assert.ok(present.length >= 3, `help.md must surface ≥3 humanized impact labels; found ${present.length}: ${present.join(', ')}`);
|
|
// At least three of the userActionLanguage phrases should appear
|
|
const actions = ['Fix this now', 'Fix soon', 'Fix when convenient', 'Optional cleanup', 'FYI'];
|
|
const presentActions = actions.filter(a => content.includes(a));
|
|
assert.ok(presentActions.length >= 3, `help.md must surface ≥3 humanized action phrases; found ${presentActions.length}: ${presentActions.join(', ')}`);
|
|
});
|
|
|
|
test('help.md: no bare "PreToolUse" jargon in user-facing copy', async () => {
|
|
const content = await readCommand('help.md');
|
|
// Allow the word in code/quoted contexts but the body table descriptions should not lean on it.
|
|
// Heuristic: no occurrence of "PreToolUse" outside of code spans / quoted blocks.
|
|
// Simple check: no "PreToolUse" anywhere except in any backtick span — since this file is doc-only,
|
|
// require zero occurrences.
|
|
assert.doesNotMatch(content, /\bPreToolUse\b/, 'help.md user copy must not lean on "PreToolUse" jargon — use plain language');
|
|
});
|
|
|
|
test('help.md: no bare "frontmatter" jargon in user-facing copy', async () => {
|
|
const content = await readCommand('help.md');
|
|
assert.doesNotMatch(content, /\bfrontmatter\b/, 'help.md user copy must not lean on "frontmatter" jargon — use plain language ("metadata block at the top of each file")');
|
|
});
|