deprecopilot
Version:
Automated dependency management with AI-powered codemods
332 lines (294 loc) • 10.9 kB
JavaScript
#!/usr/bin/env node
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
const pkg = require('../package.json')
import updateNotifier from 'update-notifier'
import { audit } from '../dist/commands/audit.js'
import { upgrade } from '../dist/commands/upgrade.js'
import { fix } from '../dist/commands/fix.js'
import { telemetry } from '../dist/commands/telemetry.js'
import { logger } from '../dist/lib/logger.js'
import inquirer from 'inquirer'
updateNotifier({ pkg }).notify()
const args = process.argv.slice(2)
const command = args[0]
function extractAIFlags(args) {
const flags = {}
for (const arg of args) {
if (arg === '--ai') flags.ai = true
if (arg === '--no-ai') flags.ai = false
if (arg.startsWith('--llm-provider=')) flags.llmProvider = arg.split('=')[1]
}
return flags
}
function showHelp() {
process.stdout.write(`Usage: deprecopilot <command> [options]
Commands:
audit Audit dependencies for outdated and vulnerable packages
upgrade Upgrade dependencies with optional codemods
fix Apply codemods to fix breaking changes
telemetry Manage telemetry settings
Global Options:
--verbose, -v Enable verbose output
--silent, -s Suppress all output
--json Output results in JSON format
--log-file=FILE Write logs to specified file
--help, -h Show command help
--version, -V Show version information
AI Codemod Options:
--ai Enable AI-driven codemod generation (default: off)
--no-ai Disable AI codemods
--llm-provider Specify LLM provider (default: gemini)
--preview Show codemod diff preview, do not modify files
Examples:
deprecopilot audit
deprecopilot fix --preview --ai
deprecopilot upgrade lodash --ai
deprecopilot telemetry status
For more information, see: https://github.com/triallord/deprecopilot
`)
}
function showAuditHelp() {
process.stdout.write(`Usage: deprecopilot audit [options]
Audit your project for outdated and vulnerable dependencies.
Options:
--json Output results in JSON format
--pretty Pretty-print JSON output
--strict Enable strict security auditing
--verbose Show detailed information
--silent Suppress output
Examples:
deprecopilot audit
deprecopilot audit --json
deprecopilot audit --strict --verbose
For more information, see: https://github.com/triallord/deprecopilot/docs/cli.md
`)
}
function showUpgradeHelp() {
process.stdout.write(`Usage: deprecopilot upgrade [packages...] [options]
Upgrade dependencies to newer versions with optional codemod application.
Arguments:
packages... Specific packages to upgrade (optional, upgrades all if not specified)
Options:
--ai Enable AI-driven codemod generation
--no-ai Disable AI codemods
--llm-provider Specify LLM provider (default: gemini)
--dry-run Show what would be upgraded without making changes
--yes Skip confirmation prompts
--interactive Interactive mode with prompts
--json Output results in JSON format
--verbose Show detailed information
--silent Suppress output
Examples:
deprecopilot upgrade lodash express
deprecopilot upgrade --interactive
deprecopilot upgrade lodash --ai --dry-run
deprecopilot upgrade --ai --llm-provider openai
For more information, see: https://github.com/triallord/deprecopilot/docs/cli.md
`)
}
function showFixHelp() {
process.stdout.write(`Usage: deprecopilot fix [options]
Apply codemods to fix breaking changes from dependency upgrades.
Options:
--preview Show codemod diff preview, do not modify files
--all Apply codemods to all upgradable dependencies
--ai Enable AI-driven codemod generation
--no-ai Disable AI codemods
--llm-provider Specify LLM provider (default: gemini)
--dry-run Show what would be changed without applying
--json Output results in JSON format
--verbose Show detailed information
--silent Suppress output
Examples:
deprecopilot fix --preview
deprecopilot fix --all --ai
deprecopilot fix --preview --json
deprecopilot fix --dry-run --ai
For more information, see: https://github.com/triallord/deprecopilot/docs/cli.md
`)
}
function showTelemetryHelp() {
process.stdout.write(`Usage: deprecopilot telemetry <command>
Manage telemetry settings for deprecopilot.
Commands:
enable Enable telemetry collection
disable Disable telemetry collection
status Show current telemetry status
Examples:
deprecopilot telemetry enable
deprecopilot telemetry disable
deprecopilot telemetry status
Telemetry is strictly opt-in and disabled by default.
See PRIVACY.md for details about data collection and usage.
For more information, see: https://github.com/triallord/deprecopilot/docs/cli.md
`)
}
async function main() {
const start = Date.now()
let exitCode = 0
// Parse global flags
const globalFlags = { verbose: false, silent: false, json: false, logFile: null }
for (const arg of args) {
if (arg === '--verbose') globalFlags.verbose = true
if (arg === '--silent') globalFlags.silent = true
if (arg === '--json') globalFlags.json = true
if (arg.startsWith('--log-file=')) globalFlags.logFile = arg.split('=')[1]
}
logger.setVerbosity(globalFlags)
if (globalFlags.logFile) logger.setLogFile(globalFlags.logFile)
// Simplified context without plugins to avoid hanging
const context = { plugins: [] }
// Debug: log the command being executed
console.error('DEBUG: command =', command)
console.error('DEBUG: args =', args)
try {
switch (command) {
case 'audit': {
if (args.includes('--help') || args.includes('-h')) {
showAuditHelp()
process.exit(0)
}
const flags = {}
for (const arg of args.slice(1)) {
if (arg === '--json') flags.json = true
if (arg === '--pretty') flags.pretty = true
if (arg === '--strict') flags.strict = true
if (arg === '--verbose') flags.verbose = true
if (arg === '--silent') flags.silent = true
}
try {
const exitCode = await audit(flags, context)
process.exit(exitCode)
} catch (error) {
console.error('DEBUG: Audit error:', error)
process.exit(1)
}
break
}
case 'upgrade': {
if (args.includes('--help') || args.includes('-h')) {
showUpgradeHelp()
process.exit(0)
}
if (args.includes('--interactive')) {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'package',
message: 'Which package do you want to upgrade?',
validate: v => v ? true : 'Package name is required',
},
{
type: 'confirm',
name: 'ai',
message: 'Use AI codemod?',
default: false,
},
{
type: 'confirm',
name: 'dryRun',
message: 'Dry run (no changes)?',
default: true,
},
{
type: 'list',
name: 'output',
message: 'Output format?',
choices: [
{ name: 'Pretty', value: 'pretty' },
{ name: 'JSON', value: 'json' },
],
default: 'pretty',
},
])
const flags = {
ai: answers.ai,
dryRun: answers.dryRun,
json: answers.output === 'json',
verbose: globalFlags.verbose,
silent: globalFlags.silent,
}
const exitCode = await upgrade([answers.package], flags, context)
process.exit(exitCode)
break
}
const upArgs = []
const flags = {}
for (const arg of args.slice(1)) {
if (arg === '--ai') flags.ai = true
else if (arg === '--no-ai') flags.ai = false
else if (arg.startsWith('--llm-provider=')) flags.llmProvider = arg.split('=')[1]
else if (arg === '--dry-run') flags.dryRun = true
else if (arg === '--yes') flags.yes = true
else if (arg.startsWith('--test=')) flags.test = arg.slice(7)
else if (arg === '--no-codemod') flags.noCodemod = true
else if (arg === '--rollback') flags.rollback = true
else if (arg === '--verbose') flags.verbose = true
else if (arg === '--silent') flags.silent = true
else if (arg === '--json') flags.json = true
else upArgs.push(arg)
}
const exitCode = await upgrade(upArgs, flags, context)
process.exit(exitCode)
break
}
case 'fix': {
if (args.includes('--help') || args.includes('-h')) {
showFixHelp()
process.exit(0)
}
const flags = {}
for (const arg of args.slice(1)) {
if (arg === '--json') flags.json = true
if (arg === '--all') flags.all = true
if (arg === '--dry-run') flags.dryRun = true
if (arg === '--ai') flags.ai = true
if (arg === '--no-ai') flags.ai = false
if (arg.startsWith('--llm-provider=')) flags.llmProvider = arg.split('=')[1]
if (arg === '--verbose') flags.verbose = true
if (arg === '--silent') flags.silent = true
if (arg === '--preview') flags.previewOnly = true
if (arg === '--breaking-changes') flags.breakingChanges = true
}
await fix(flags, context)
process.exit(0)
break
}
case 'telemetry': {
if (args.includes('--help') || args.includes('-h')) {
showTelemetryHelp()
process.exit(0)
}
const exitCode = await telemetry(args.slice(1))
process.exit(exitCode)
break
}
case '--help':
case '-h': {
showHelp()
process.exit(0)
}
case '--version':
case '-v': {
process.stdout.write(`deprecopilot version ${pkg.version}\n`)
process.exit(0)
}
default: {
if (!command) {
showHelp()
process.exit(1)
} else {
process.stdout.write(`Unknown command: ${command}\n`)
showHelp()
process.exit(1)
}
}
}
} catch (e) {
console.error('DEBUG: Main error:', e)
exitCode = 1
process.exit(exitCode)
}
}
main()