mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 23:56:29 +03:00
The install completion message said to run /impeccable init "in your AI harness", and users pasted it into their shell instead (bash: /impeccable: No such file or directory). Say the command is typed in the AI coding agent's chat, and give `npx impeccable init` a pointed redirect instead of the generic unknown-command error. A real path named `init` still routes to detect as before. Prepared with AI assistance (Cursor agent), directed by @abdulwahabone. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -77,6 +77,12 @@ Compatibility:
|
||||
process.argv = [process.argv[0], process.argv[1], ...args];
|
||||
const { detectCli } = await import('../engine/detect-antipatterns.mjs');
|
||||
await detectCli();
|
||||
} else if (command === 'init') {
|
||||
// The follow-up mistake from issue #472: `/impeccable init` belongs in an AI
|
||||
// coding agent's chat, and a user who typed it into their shell is likely to
|
||||
// retry it here as `npx impeccable init`.
|
||||
console.error(`"init" is not a CLI command. Type /impeccable init in your AI coding agent's chat (Claude Code, Cursor, Codex, ...), not in this terminal.`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
// An unknown bareword: a mistyped command (or an old cached version run
|
||||
// against newer docs). Fail loudly instead of silently statting it as a path.
|
||||
|
||||
@@ -1944,7 +1944,7 @@ async function install(flags) {
|
||||
reportProviderAgents(agentResults);
|
||||
if (hookTargets.length > 0) console.log(`Installed hooks into: ${hookTargets.join(', ')}`);
|
||||
|
||||
console.log('\nDone! Run /impeccable init in your AI harness to set up design context.\n');
|
||||
console.log('\nDone! Now type /impeccable init in your AI coding agent\'s chat (not in this terminal) to set up design context.\n');
|
||||
}
|
||||
|
||||
// ─── skills update ────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -719,6 +719,64 @@ describe('skills install/update: local universal bundle e2e', () => {
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
}, 15000);
|
||||
|
||||
test('install completion says /impeccable init runs in the agent chat, not the terminal (#472)', () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'imp-test-install-472-msg-'));
|
||||
const home = mkdtempSync(join(tmpdir(), 'imp-home-install-472-msg-'));
|
||||
execSync('git init', { cwd: tmp });
|
||||
const bundleRoot = createFakeUniversalBundle(tmp, ['.claude']);
|
||||
|
||||
const output = run('install -y --providers=claude --no-hooks', {
|
||||
cwd: tmp,
|
||||
env: { ...process.env, HOME: home, IMPECCABLE_BUNDLE_PATH: bundleRoot },
|
||||
});
|
||||
|
||||
expect(output).toContain("type /impeccable init in your AI coding agent's chat (not in this terminal)");
|
||||
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
}, 15000);
|
||||
|
||||
test('`impeccable init` in the shell points at the agent chat instead of "Unknown command" (#472)', () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'imp-test-init-472-'));
|
||||
|
||||
let error;
|
||||
try {
|
||||
run('init', { cwd: tmp, stdio: 'pipe' });
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error).toBeDefined();
|
||||
expect(error.status).toBe(1);
|
||||
const stderr = String(error.stderr);
|
||||
expect(stderr).toContain("Type /impeccable init in your AI coding agent's chat");
|
||||
expect(stderr).not.toContain('Unknown command');
|
||||
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
}, 15000);
|
||||
|
||||
test('a real path named init still routes to detect, not the #472 guidance', () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'imp-test-init-path-472-'));
|
||||
mkdirSync(join(tmp, 'init'), { recursive: true });
|
||||
writeFileSync(join(tmp, 'init', 'page.html'), '<!doctype html><html><head><title>t</title></head><body><p>hello</p></body></html>\n');
|
||||
|
||||
// Detect exits 0 on a clean scan and 2 when findings surface; either way it
|
||||
// must be the detector answering, not the init redirect. --json makes that
|
||||
// positive: the detector always prints a JSON findings array.
|
||||
let output = '';
|
||||
try {
|
||||
output = run('init --json', { cwd: tmp, stdio: 'pipe' });
|
||||
} catch (e) {
|
||||
output = `${e.stdout || ''}${e.stderr || ''}`;
|
||||
}
|
||||
|
||||
expect(output.trim().startsWith('[')).toBe(true);
|
||||
expect(output).not.toContain('is not a CLI command');
|
||||
expect(output).not.toContain('Unknown command');
|
||||
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
}, 60000);
|
||||
|
||||
test('formats detected harnesses as concise source-to-target rows', () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'imp-test-detect-lines-'));
|
||||
const home = mkdtempSync(join(tmpdir(), 'imp-home-detect-lines-'));
|
||||
|
||||
Reference in New Issue
Block a user