Skip to content

📝 Improve best practices compliance (POSIX, Node.js standards) #70

@ryota-murakami

Description

@ryota-murakami

Problem

The project follows many Node.js CLI best practices but is missing some standard conventions that improve user experience and compatibility.

Based on nodejs-cli-apps-best-practices and 2025 Node.js standards.

Missing Best Practices

1. No Top-Level --version Flag

Current: Version only shown via git gpt config subcommand
Expected: Standard -v, --version flag

# Current - not working
$ git gpt --version
# Invalid command

# Expected behavior
$ git gpt --version
0.10.2

$ git gpt -v
0.10.2

Implementation:

import { readFileSync } from 'fs'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const packageJson = JSON.parse(
  readFileSync(join(__dirname, 'package.json'), 'utf8')
)

program
  .name('git-gpt')
  .description('AI-powered Git commit message generator')
  .version(packageJson.version, '-v, --version', 'Output the version number')
  .helpOption('-h, --help', 'Display help for command')

2. No Node.js Version Enforcement

Current: Volta specifies v22.18.0, but no package.json enforcement
Risk: Users on old Node.js versions may encounter runtime errors

Add to package.json:

{
  "engines": {
    "node": ">=18.0.0"
  }
}

Why Node 18+:

  • Native ES Modules support (required by project)
  • Stable fetch API
  • Updated OpenAI SDK requirements
  • Long-term support (LTS)

3. Missing .editorconfig

Current: Only .prettierrc for formatting
Issue: Different editors may use different settings

Create .editorconfig:

# EditorConfig: https://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,json,md,yml,yaml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[package.json]
indent_size = 2

4. API Key Format Validation

Current: No validation of OpenAI API key format
Issue: Cryptic errors when invalid key is used

/**
 * Validates OpenAI API key format
 * @param {string} key - API key to validate
 * @returns {boolean} True if valid format
 */
function isValidOpenAIKey(key) {
  // OpenAI keys start with 'sk-' or 'sk-proj-'
  // Followed by alphanumeric characters
  return /^sk-[a-zA-Z0-9-_]{20,}$/.test(key)
}

// In open-api-key command
if (response.value) {
  if (!isValidOpenAIKey(response.value)) {
    console.error('❌ Invalid API key format.')
    console.error('   OpenAI keys should start with "sk-"')
    console.error('   Get your key at: https://platform.openai.com/api-keys')
    return
  }
  
  saveConfig({ apiKey: response.value })
  apiKey = response.value
  console.log('✅ API key saved to configuration.')
}

5. Environment Variable Validation

Current: Silent fallback to .env if config key missing
Better: Validate and provide clear guidance

/**
 * Gets OpenAI API key with validation and helpful errors
 * @returns {string} Valid API key
 * @throws {Error} If no key found or invalid format
 */
function getValidatedApiKey() {
  // Priority: config file > .env file
  const key = apiKey || process.env.OPENAI_API_KEY
  
  if (!key) {
    console.error('❌ No OpenAI API key found.')
    console.error('\nOptions:')
    console.error('  1. Set via command: git gpt open-api-key add')
    console.error('  2. Set in .env file: OPENAI_API_KEY=sk-...')
    console.error('\nGet your key at: https://platform.openai.com/api-keys')
    process.exit(1)
  }
  
  if (!isValidOpenAIKey(key)) {
    console.error('❌ Invalid OpenAI API key format.')
    console.error('   Keys should start with "sk-"')
    console.error('\nUpdate your key: git gpt open-api-key add')
    process.exit(1)
  }
  
  return key
}

6. Exit Code Standardization

Current: All errors exit with code 1
Better: Use standard exit codes

const EXIT_CODES = {
  SUCCESS: 0,
  GENERAL_ERROR: 1,
  INVALID_USAGE: 2,
  CONFIG_ERROR: 3,
  API_ERROR: 4,
  NETWORK_ERROR: 5,
  GIT_ERROR: 6,
}

// Usage
if (!gitDiff) {
  console.log('No changes to commit.')
  process.exit(EXIT_CODES.SUCCESS) // Not an error
}

if (error.status === 401) {
  console.error('Invalid API key')
  process.exit(EXIT_CODES.API_ERROR)
}

7. Signal Handling (Graceful Shutdown)

Current: No cleanup on SIGINT/SIGTERM
Better: Handle signals gracefully

// Graceful shutdown
process.on('SIGINT', () => {
  console.log('\n\n👋 Commit canceled by user.')
  process.exit(EXIT_CODES.SUCCESS)
})

process.on('SIGTERM', () => {
  console.log('\n\n👋 Process terminated.')
  process.exit(EXIT_CODES.SUCCESS)
})

// Cleanup on exit
process.on('exit', (code) => {
  // Cleanup temporary files if any
  // Close file handles if any
})

Implementation Checklist

High Priority

  • Add --version / -v top-level flag
  • Add engines field to package.json
  • Add API key format validation
  • Improve environment variable error messages

Medium Priority

  • Create .editorconfig file
  • Standardize exit codes
  • Add signal handling (SIGINT, SIGTERM)

Low Priority

  • Add --help customization for each command
  • Consider adding --quiet / -q flag for scripting
  • Consider adding --dry-run flag to preview message

Benefits

  • ✅ Better user experience
  • ✅ Standard CLI conventions
  • ✅ Cross-platform compatibility
  • ✅ Better error messages
  • ✅ Easier debugging

Acceptance Criteria

  • git gpt --version works
  • git gpt -v works
  • Node.js version checked on install
  • API key format validated on save
  • .editorconfig created
  • Exit codes standardized
  • Signal handling implemented
  • Tests updated for new behavior
  • Documentation updated

Priority

Low-Medium - Nice to have, improves polish

Related

Quality analysis report: claudedocs/quality-analysis-report.md section 6

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions