pin.mjs

  1#!/usr/bin/env node
  2/**
  3 * Pin/unpin sub-commands as standalone skill shortcuts.
  4 *
  5 * Usage:
  6 *   node <scripts_path>/pin.mjs pin <command>
  7 *   node <scripts_path>/pin.mjs unpin <command>
  8 *
  9 * `pin audit` creates a lightweight /audit skill that redirects to /impeccable audit.
 10 * `unpin audit` removes that shortcut.
 11 *
 12 * The script discovers harness directories (.claude/skills, .cursor/skills, etc.)
 13 * in the project root and creates/removes the pin in all of them.
 14 */
 15
 16import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync } from 'node:fs';
 17import { join, resolve, dirname } from 'node:path';
 18import { fileURLToPath } from 'node:url';
 19
 20const __dirname = dirname(fileURLToPath(import.meta.url));
 21
 22// All known harness directories
 23const HARNESS_DIRS = [
 24  '.claude', '.cursor', '.gemini', '.codex', '.agents',
 25  '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',
 26];
 27
 28// Valid sub-command names
 29const VALID_COMMANDS = [
 30  'craft', 'teach', 'extract', 'document', 'shape',
 31  'critique', 'audit',
 32  'polish', 'bolder', 'quieter', 'distill', 'harden', 'onboard', 'live',
 33  'animate', 'colorize', 'typeset', 'layout', 'delight', 'overdrive',
 34  'clarify', 'adapt', 'optimize',
 35];
 36
 37// Marker to identify pinned skills (so unpin doesn't delete user skills)
 38const PIN_MARKER = '<!-- impeccable-pinned-skill -->';
 39
 40/**
 41 * Walk up from startDir to find a project root.
 42 */
 43function findProjectRoot(startDir = process.cwd()) {
 44  let dir = resolve(startDir);
 45  while (dir !== '/') {
 46    if (
 47      existsSync(join(dir, 'package.json')) ||
 48      existsSync(join(dir, '.git')) ||
 49      existsSync(join(dir, 'skills-lock.json'))
 50    ) {
 51      return dir;
 52    }
 53    const parent = resolve(dir, '..');
 54    if (parent === dir) break;
 55    dir = parent;
 56  }
 57  return resolve(startDir);
 58}
 59
 60/**
 61 * Find harness skill directories that have an impeccable skill installed.
 62 */
 63function findHarnessDirs(projectRoot) {
 64  const dirs = [];
 65  for (const harness of HARNESS_DIRS) {
 66    const skillsDir = join(projectRoot, harness, 'skills');
 67    // Only pin in harness dirs that already have impeccable installed
 68    const impeccableDir = join(skillsDir, 'impeccable');
 69    if (existsSync(impeccableDir) || existsSync(join(skillsDir, 'i-impeccable'))) {
 70      dirs.push(skillsDir);
 71    }
 72  }
 73  return dirs;
 74}
 75
 76/**
 77 * Load command metadata (descriptions for pinned skills).
 78 */
 79function loadCommandMetadata() {
 80  const metadataPath = join(__dirname, 'command-metadata.json');
 81  if (existsSync(metadataPath)) {
 82    return JSON.parse(readFileSync(metadataPath, 'utf-8'));
 83  }
 84  return {};
 85}
 86
 87/**
 88 * Generate a pinned skill's SKILL.md content.
 89 */
 90function generatePinnedSkill(command, metadata) {
 91  const desc = metadata[command]?.description || `Shortcut for /impeccable ${command}.`;
 92  const hint = metadata[command]?.argumentHint || '[target]';
 93
 94  return `---
 95name: ${command}
 96description: "${desc}"
 97argument-hint: "${hint}"
 98user-invocable: true
 99---
100
101${PIN_MARKER}
102
103This is a pinned shortcut for \`{{command_prefix}}impeccable ${command}\`.
104
105Invoke {{command_prefix}}impeccable ${command}, passing along any arguments provided here, and follow its instructions.
106`;
107}
108
109/**
110 * Pin a command: create shortcut skill in all harness dirs.
111 */
112function pin(command, projectRoot) {
113  const metadata = loadCommandMetadata();
114  const harnessDirs = findHarnessDirs(projectRoot);
115
116  if (harnessDirs.length === 0) {
117    console.log('No harness directories with impeccable installed found.');
118    return false;
119  }
120
121  const content = generatePinnedSkill(command, metadata);
122  let created = 0;
123
124  for (const skillsDir of harnessDirs) {
125    // Check if skill already exists (and isn't a pin)
126    const skillDir = join(skillsDir, command);
127    if (existsSync(skillDir)) {
128      const existingMd = join(skillDir, 'SKILL.md');
129      if (existsSync(existingMd)) {
130        const existing = readFileSync(existingMd, 'utf-8');
131        if (!existing.includes(PIN_MARKER)) {
132          console.log(`  SKIP: ${skillDir} (non-pinned skill already exists)`);
133          continue;
134        }
135      }
136    }
137
138    mkdirSync(skillDir, { recursive: true });
139    writeFileSync(join(skillDir, 'SKILL.md'), content, 'utf-8');
140    console.log(`  + ${skillDir}`);
141    created++;
142  }
143
144  if (created > 0) {
145    console.log(`\nPinned '${command}' as a standalone shortcut in ${created} location(s).`);
146    console.log(`You can now use /${command} directly.`);
147  }
148
149  return created > 0;
150}
151
152/**
153 * Unpin a command: remove shortcut skill from all harness dirs.
154 */
155function unpin(command, projectRoot) {
156  const harnessDirs = findHarnessDirs(projectRoot);
157  let removed = 0;
158
159  for (const skillsDir of harnessDirs) {
160    const skillDir = join(skillsDir, command);
161    if (!existsSync(skillDir)) continue;
162
163    const skillMd = join(skillDir, 'SKILL.md');
164    if (!existsSync(skillMd)) continue;
165
166    // Safety: only remove if it's a pinned skill
167    const content = readFileSync(skillMd, 'utf-8');
168    if (!content.includes(PIN_MARKER)) {
169      console.log(`  SKIP: ${skillDir} (not a pinned skill)`);
170      continue;
171    }
172
173    rmSync(skillDir, { recursive: true, force: true });
174    console.log(`  - ${skillDir}`);
175    removed++;
176  }
177
178  if (removed > 0) {
179    console.log(`\nUnpinned '${command}' from ${removed} location(s).`);
180    console.log(`Use /impeccable ${command} to access it.`);
181  } else {
182    console.log(`No pinned '${command}' shortcut found.`);
183  }
184
185  return removed > 0;
186}
187
188// --- CLI ---
189const [,, action, command] = process.argv;
190
191if (!action || !command) {
192  console.log('Usage: node pin.mjs <pin|unpin> <command>');
193  console.log(`\nAvailable commands: ${VALID_COMMANDS.join(', ')}`);
194  process.exit(1);
195}
196
197if (action !== 'pin' && action !== 'unpin') {
198  console.error(`Unknown action: ${action}. Use 'pin' or 'unpin'.`);
199  process.exit(1);
200}
201
202if (!VALID_COMMANDS.includes(command)) {
203  console.error(`Unknown command: ${command}`);
204  console.error(`Available commands: ${VALID_COMMANDS.join(', ')}`);
205  process.exit(1);
206}
207
208const root = findProjectRoot();
209
210if (action === 'pin') {
211  pin(command, root);
212} else {
213  unpin(command, root);
214}