instruqt
Version:
CLI tool for deploying AI agent context documentation across multiple platforms with dual MERN/module support
148 lines (128 loc) ⢠5.25 kB
JavaScript
/**
* @file CLI wrapper for pack application system
* @description Provides instruqt apply command for user-customizable context documents
* @usage npx instruqt apply <pack-spec> [--plan]
*
* RATIONALE: Separates pack application from original context deployment to maintain
* backward compatibility while adding powerful customization capabilities. Users can
* choose between built-in contexts (instruct) or custom packs (apply).
*
* DESIGN DECISIONS:
* 1. Separate command: apply vs instruct maintains clear separation of concerns
* 2. CommonJS compatibility: Works with existing project structure
* 3. Comprehensive help: Reduces learning curve for pack system adoption
* 4. Plan mode: Enables safe preview of changes before application
*/
const { apply, plan } = require('../lib/packs');
const path = require('path');
/**
* Display usage information and examples
*
* RATIONALE: Comprehensive help reduces support burden and demonstrates
* the flexibility of the pack system through concrete examples.
*/
function showUsage() {
console.log('Usage: instruqt apply <pack-spec> [options]');
console.log('');
console.log('Pack Specifications:');
console.log(' ./path/to/pack Use local folder');
console.log(' alias-name Use alias from instruqt.config.json');
console.log(' @scope/package Use npm package');
console.log(' pack-name Use pack from ~/.config/instruqt/packs/');
console.log('');
console.log('Options:');
console.log(' --plan Preview changes without applying');
console.log(' --help, -h Show this help message');
console.log('');
console.log('Examples:');
console.log(' instruqt apply ./instruqt/packs/my-pack');
console.log(' instruqt apply local-mern --plan');
console.log(' instruqt apply @acme-instruqt/nextjs-team');
console.log(' instruqt apply my-custom-pack');
console.log('');
console.log('Pack Structure:');
console.log(' my-pack/');
console.log(' pack.json Pack manifest');
console.log(' files/ Files to copy');
console.log(' README.md');
console.log(' agent-prompt.md');
console.log('');
console.log('Configuration (optional):');
console.log(' Create instruqt.config.json in project root:');
console.log(' {');
console.log(' "packs": {');
console.log(' "local-mern": "./instruqt/packs/mern-basic",');
console.log(' "team-next": "@acme-instruqt/nextjs-team"');
console.log(' }');
console.log(' }');
}
/**
* Apply pack with user feedback
* @param {string} spec - Pack specification
* @param {boolean} dryRun - Whether to preview instead of apply
*
* DESIGN DECISIONS:
* 1. Detailed output: Shows every operation for transparency
* 2. Action indicators: Clear visual distinction between operations
* 3. Error context: Helpful guidance when operations fail
* 4. Exit codes: Proper CLI behavior for CI/CD integration
*/
async function applyPack(spec, dryRun = false) {
try {
console.log(`š ${dryRun ? 'Planning' : 'Applying'} pack: ${spec}\n`);
const results = await apply(spec, { dryRun });
if (dryRun) {
console.log('š Planned operations:');
} else {
console.log('ā
Applied operations:');
}
for (const result of results) {
const { src, dest, action } = result;
const icon = action === 'create' ? 'ā' :
action === 'replace' ? 'š' :
action === 'skip' ? 'āļø' : 'ā';
console.log(` ${icon} ${action}: ${path.basename(src)} ā ${dest}`);
}
const counts = results.reduce((acc, r) => {
acc[r.action] = (acc[r.action] || 0) + 1;
return acc;
}, {});
console.log(`\nš Summary: ${Object.entries(counts).map(([action, count]) => `${count} ${action}`).join(', ')}`);
if (dryRun) {
console.log('\nš” Run without --plan to apply these changes');
} else {
console.log('\nš Pack application complete!');
}
} catch (error) {
console.error(`ā Error: ${error.message}`);
// Provide helpful guidance for common errors
if (error.message.includes('not found')) {
console.error('\nš” Make sure the pack specification is correct:');
console.error(' - For local paths: ensure the directory exists');
console.error(' - For npm packages: ensure the package is installed');
console.error(' - For aliases: check your instruqt.config.json');
console.error(' - For home packs: check ~/.config/instruqt/packs/');
}
process.exit(1);
}
}
// Command line argument parsing - moved to function to avoid global scope
function parseArguments() {
const args = process.argv.slice(2);
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
showUsage();
process.exit(0);
}
const spec = args[0];
const dryRun = args.includes('--plan');
return { spec, dryRun };
}
const { spec, dryRun } = parseArguments();
// Validate pack specification
if (!spec || spec.startsWith('-')) {
console.error('ā Error: Pack specification is required');
showUsage();
process.exit(1);
}
applyPack(spec, dryRun);