tst-changelog 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -224,8 +224,15 @@ declare class ChangelogService {
224
224
  updateJson(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): ChangelogJson;
225
225
  /**
226
226
  * Write JSON changelog to file
227
+ * Applies Biome formatting: single-element arrays inline, trailing newline
227
228
  */
228
229
  writeJson(data: ChangelogJson): void;
230
+ /**
231
+ * Format JSON with Biome-compatible style:
232
+ * - Single-element arrays are inline: ["item"] instead of multiline
233
+ * - Trailing newline at end of file
234
+ */
235
+ private formatJsonForBiome;
229
236
  }
230
237
 
231
238
  export { type AIConfig, AIService, type CLIOptions, type ChangeType, type ChangelogConfig, type ChangelogEntry, type ChangelogJson, type ChangelogJsonRelease, type ChangelogMetadata, type ChangelogSection, ChangelogService, type CommitInfo, type Config, type DateGroupedCommits, type GeneratedChangelog, type GitConfig, GitService, type InitResult, type StagedChanges, type VersionedEntry, initConfig, loadConfig };
package/dist/index.js CHANGED
@@ -787,11 +787,23 @@ ${sectionLines}`;
787
787
  }
788
788
  /**
789
789
  * Write JSON changelog to file
790
+ * Applies Biome formatting: single-element arrays inline, trailing newline
790
791
  */
791
792
  writeJson(data) {
792
793
  const jsonPath = this.getJsonFilePath();
793
794
  if (!jsonPath) return;
794
- writeFileSync2(jsonPath, JSON.stringify(data, null, 2), "utf-8");
795
+ const formatted = this.formatJsonForBiome(data);
796
+ writeFileSync2(jsonPath, formatted, "utf-8");
797
+ }
798
+ /**
799
+ * Format JSON with Biome-compatible style:
800
+ * - Single-element arrays are inline: ["item"] instead of multiline
801
+ * - Trailing newline at end of file
802
+ */
803
+ formatJsonForBiome(data) {
804
+ let json = JSON.stringify(data, null, 2);
805
+ json = json.replace(/\[\n\s+("(?:[^"\\]|\\.)*")\n\s+\]/g, "[$1]");
806
+ return json + "\n";
795
807
  }
796
808
  };
797
809
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/git.ts","../src/ai.ts","../src/changelog.ts"],"sourcesContent":["import 'dotenv/config';\nimport { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, resolve } from 'node:path';\nimport { loadConfig, initConfig } from './config.js';\nimport { GitService } from './git.js';\nimport { AIService } from './ai.js';\nimport { ChangelogService } from './changelog.js';\nimport type { CLIOptions, ChangelogMetadata, CommitInfo, DateGroupedCommits, VersionedEntry } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));\n\n/**\n * Parse a semver version string and return major, minor, patch\n */\nfunction parseVersion(version: string): { major: number; minor: number; patch: number } | null {\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match) return null;\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n };\n}\n\n/**\n * Get the latest version from changelog.json\n * Returns the highest semver version found, or null if no valid versions\n */\nfunction getLatestVersionFromChangelog(jsonFilePath?: string): string | null {\n const changelogPath = jsonFilePath ?? resolve(process.cwd(), 'changelog.json');\n\n if (!existsSync(changelogPath)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(changelogPath, 'utf-8'));\n if (!data.releases || !Array.isArray(data.releases)) {\n return null;\n }\n\n let latestVersion: string | null = null;\n let latestParsed: { major: number; minor: number; patch: number } | null = null;\n\n for (const release of data.releases) {\n if (!release.version || release.version === 'Unreleased') continue;\n\n const parsed = parseVersion(release.version);\n if (!parsed) continue;\n\n if (!latestParsed ||\n parsed.major > latestParsed.major ||\n (parsed.major === latestParsed.major && parsed.minor > latestParsed.minor) ||\n (parsed.major === latestParsed.major && parsed.minor === latestParsed.minor && parsed.patch > latestParsed.patch)) {\n latestVersion = release.version;\n latestParsed = parsed;\n }\n }\n\n return latestVersion;\n } catch {\n return null;\n }\n}\n\n/**\n * Get version from package.json\n */\nfunction getVersionFromPackageJson(): { major: number; minor: number; patch: number } | null {\n const pkgPath = resolve(process.cwd(), 'package.json');\n\n if (!existsSync(pkgPath)) {\n return null;\n }\n\n try {\n const projectPkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n const currentVersion = projectPkg.version ?? '0.0.0';\n return parseVersion(currentVersion);\n } catch {\n return null;\n }\n}\n\n/**\n * Compare two versions and return the higher one\n */\nfunction getHigherVersion(\n a: { major: number; minor: number; patch: number } | null,\n b: { major: number; minor: number; patch: number } | null\n): { major: number; minor: number; patch: number } | null {\n if (!a) return b;\n if (!b) return a;\n\n if (a.major > b.major) return a;\n if (b.major > a.major) return b;\n if (a.minor > b.minor) return a;\n if (b.minor > a.minor) return b;\n if (a.patch > b.patch) return a;\n return b;\n}\n\n/**\n * Get the next minor version by comparing changelog.json and package.json\n * Uses the higher version as base, then increments minor\n */\nfunction getNextMinorVersion(jsonFilePath?: string): string {\n // Get version from changelog.json\n const latestFromChangelog = getLatestVersionFromChangelog(jsonFilePath);\n const changelogVersion = latestFromChangelog ? parseVersion(latestFromChangelog) : null;\n\n // Get version from package.json\n const pkgVersion = getVersionFromPackageJson();\n\n // Use the higher version as base\n const baseVersion = getHigherVersion(changelogVersion, pkgVersion);\n\n if (baseVersion) {\n return `${baseVersion.major}.${baseVersion.minor + 1}.0`;\n }\n\n return '0.1.0';\n}\n\n/**\n * Get base version for --from-commits mode\n * Compares changelog.json and package.json, uses the higher one\n */\nfunction getBaseVersionForFromCommits(jsonFilePath?: string): { major: number; minor: number } {\n // Get version from changelog.json\n const latestFromChangelog = getLatestVersionFromChangelog(jsonFilePath);\n const changelogVersion = latestFromChangelog ? parseVersion(latestFromChangelog) : null;\n\n // Get version from package.json\n const pkgVersion = getVersionFromPackageJson();\n\n // Use the higher version as base\n const baseVersion = getHigherVersion(changelogVersion, pkgVersion);\n\n if (baseVersion) {\n return { major: baseVersion.major, minor: baseVersion.minor };\n }\n\n return { major: 0, minor: 0 };\n}\n\n/**\n * Increment minor version from base by a given count\n * e.g., base {major: 0, minor: 5}, count 1 => \"0.6.0\"\n * base {major: 0, minor: 5}, count 3 => \"0.8.0\"\n */\nfunction incrementMinorVersion(base: { major: number; minor: number }, count: number): string {\n return `${base.major}.${base.minor + count}.0`;\n}\n\n/**\n * Group commits by their date (YYYY-MM-DD)\n */\nfunction groupCommitsByDate(commits: CommitInfo[]): DateGroupedCommits {\n const grouped: DateGroupedCommits = new Map();\n\n for (const commit of commits) {\n // Extract date part (YYYY-MM-DD) from ISO date string\n const date = commit.date.split('T')[0];\n\n if (!grouped.has(date)) {\n grouped.set(date, []);\n }\n grouped.get(date)!.push(commit);\n }\n\n return grouped;\n}\n\nconst program = new Command();\n\nprogram\n .name('tst-changelog')\n .description('AI-powered changelog generator using OpenRouter')\n .version(pkg.version);\n\nprogram\n .command('init')\n .description('Create a default configuration file')\n .option('-f, --file <name>', 'Config file name', 'tst-changelog.yaml')\n .action((options: { file: string }) => {\n try {\n const result = initConfig(options.file);\n console.log(`Created config file: ${result.configPath}`);\n\n if (result.huskyConfigured) {\n console.log(`Configured husky hook: ${result.huskyHook}`);\n }\n\n console.log('\\nNext steps:');\n console.log('1. Set the OPENROUTER_API_KEY environment variable');\n console.log('2. Adjust settings in the config file as needed');\n if (!result.huskyConfigured) {\n console.log('3. Run: npx tst-changelog generate');\n }\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('generate', { isDefault: true })\n .description('Generate changelog from staged changes or commit history')\n .option('-c, --config <path>', 'Path to config file')\n .option('-d, --dry-run', 'Preview without modifying files')\n .option('-v, --verbose', 'Enable verbose output')\n .option('--from-commits <count>', 'Generate from last N commits instead of staged changes', parseInt)\n .option('--version <version>', 'Version label for the changelog entry (default: \"Unreleased\" or date for --from-commits)')\n .action(run);\n\nasync function run(options: CLIOptions): Promise<void> {\n const verbose = options.verbose ?? false;\n\n try {\n // Load configuration\n if (verbose) console.log('Loading configuration...');\n const config = loadConfig(options.config);\n if (verbose) console.log('Config loaded:', JSON.stringify(config, null, 2));\n\n // Initialize services\n const git = new GitService(config.git);\n const ai = new AIService(config.ai);\n const changelog = new ChangelogService(config.changelog);\n\n // Check if we're in a git repo\n if (!(await git.isGitRepo())) {\n console.error('Error: Not a git repository');\n process.exit(1);\n }\n\n if (options.fromCommits) {\n // === FROM COMMITS MODE: Group by date, generate per-date entries ===\n if (verbose) console.log(`Getting last ${options.fromCommits} commits...`);\n const commits = await git.getRecentCommits(options.fromCommits);\n\n if (commits.length === 0) {\n console.log('No commits found.');\n process.exit(0);\n }\n\n if (verbose) console.log(`Found ${commits.length} commits`);\n\n // Group commits by date\n const groupedByDate = groupCommitsByDate(commits);\n const sortedDates = [...groupedByDate.keys()].sort(); // ascending (oldest first)\n\n if (verbose) {\n console.log(`Grouped into ${sortedDates.length} date(s):`);\n for (const date of sortedDates) {\n const dateCommits = groupedByDate.get(date)!;\n console.log(` ${date}: ${dateCommits.length} commit(s)`);\n }\n }\n\n // Get base version from changelog.json (or package.json as fallback)\n const baseVersion = getBaseVersionForFromCommits(changelog.getJsonFilePath() ?? undefined);\n if (verbose) console.log(`Base version: ${baseVersion.major}.${baseVersion.minor}.0`);\n\n // Generate changelog entries for each date (oldest to newest)\n const entries: VersionedEntry[] = [];\n const emptyStaged = { files: [], diff: '' };\n\n for (let i = 0; i < sortedDates.length; i++) {\n const date = sortedDates[i];\n const dateCommits = groupedByDate.get(date)!;\n const version = incrementMinorVersion(baseVersion, i + 1);\n\n if (verbose) console.log(`\\nGenerating changelog for ${date} (${version})...`);\n console.log(`Generating changelog for ${date}...`);\n\n const generated = await ai.generateChangelog(dateCommits, emptyStaged);\n\n if (generated.sections.length === 0) {\n if (verbose) console.log(` No entries generated for ${date}, skipping.`);\n continue;\n }\n\n if (verbose) {\n console.log(` Generated sections for ${date}:`);\n for (const section of generated.sections) {\n console.log(` ${section.type}:`);\n for (const item of section.items) {\n console.log(` - ${item}`);\n }\n }\n }\n\n entries.push({ version, date, generated });\n }\n\n if (entries.length === 0) {\n console.log('No changelog entries generated.');\n process.exit(0);\n }\n\n // Reverse for changelog (newest first)\n entries.reverse();\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n if (changelog.getJsonFilePath()) {\n console.log('Would update JSON at:', changelog.getJsonFilePath());\n }\n console.log(`\\n--- ${entries.length} new entries (newest first) ---\\n`);\n console.log(changelog.formatMultipleEntries(entries));\n console.log('\\n--- JSON releases ---');\n for (const entry of entries) {\n console.log(JSON.stringify({ version: entry.version, date: entry.date }, null, 2));\n }\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Update changelog (MD) with multiple entries\n const newContent = changelog.updateWithMultipleEntries(entries);\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n // Update changelog (JSON) with multiple entries\n if (changelog.getJsonFilePath()) {\n const jsonData = changelog.updateJsonWithMultipleEntries(entries);\n changelog.writeJson(jsonData);\n console.log(`Updated: ${changelog.getJsonFilePath()}`);\n }\n\n console.log(`Done! Created ${entries.length} version entries.`);\n\n } else {\n // === STAGED CHANGES MODE: Original behavior ===\n if (verbose) console.log('Getting staged changes...');\n const staged = await git.getStagedChanges();\n\n if (staged.files.length === 0) {\n console.log('No staged changes found. Stage some changes first.');\n process.exit(0);\n }\n\n if (verbose) {\n console.log(`Staged files: ${staged.files.join(', ')}`);\n console.log(`Diff length: ${staged.diff.length} chars`);\n }\n\n // Get recent commits for context\n if (verbose) console.log('Getting recent commits...');\n const commits = await git.getUnmergedCommits();\n if (verbose) console.log(`Found ${commits.length} unmerged commits`);\n\n // Generate changelog using AI\n console.log('Generating changelog with AI...');\n const generated = await ai.generateChangelog(commits, staged);\n\n if (generated.sections.length === 0) {\n console.log('No changelog entries generated.');\n if (verbose) console.log('Raw AI response:', generated.raw);\n process.exit(0);\n }\n\n if (verbose) {\n console.log('Generated sections:');\n for (const section of generated.sections) {\n console.log(` ${section.type}:`);\n for (const item of section.items) {\n console.log(` - ${item}`);\n }\n }\n }\n\n // Collect metadata for changelog entry\n const [author, commitHash] = await Promise.all([\n git.getCurrentUser(),\n git.getHeadCommit(),\n ]);\n const metadata: ChangelogMetadata = {\n author: author || undefined,\n commitHash: commitHash || undefined,\n timestamp: new Date(),\n };\n\n if (verbose) {\n console.log('Metadata:', metadata);\n }\n\n // Determine version label (always use next minor version)\n const version = options.version ?? getNextMinorVersion(changelog.getJsonFilePath() ?? undefined);\n\n // Update changelog (MD)\n const newContent = changelog.update(generated, version, metadata);\n\n // Update changelog (JSON)\n const jsonData = changelog.updateJson(generated, version, metadata);\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n if (changelog.getJsonFilePath()) {\n console.log('Would update JSON at:', changelog.getJsonFilePath());\n }\n console.log('\\n--- New MD entry ---');\n console.log(changelog.formatEntry(generated, version, metadata));\n console.log('\\n--- New JSON entry ---');\n console.log(JSON.stringify(jsonData.releases[0], null, 2));\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Write changelog (MD)\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n // Write changelog (JSON)\n if (changelog.getJsonFilePath()) {\n changelog.writeJson(jsonData);\n console.log(`Updated: ${changelog.getJsonFilePath()}`);\n }\n\n // Auto-stage changelog files\n await git.stageFile(config.changelog.file);\n if (config.changelog.jsonFile) {\n await git.stageFile(config.changelog.jsonFile);\n }\n console.log('Staged changelog files');\n\n console.log('Done!');\n }\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n if (verbose && error instanceof Error) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n}\n\nprogram.parse();\n\n// Export for programmatic usage\nexport { loadConfig, initConfig, type InitResult } from './config.js';\nexport { GitService } from './git.js';\nexport { AIService } from './ai.js';\nexport { ChangelogService } from './changelog.js';\nexport * from './types.js';\n","import { readFileSync, existsSync, writeFileSync, appendFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { parse, stringify } from 'yaml';\nimport type { Config } from './types.js';\n\n/**\n * Get repository URL from git remote origin\n * Normalizes SSH URLs to HTTPS for web links\n */\nfunction getRepoUrlFromGit(): string {\n try {\n const url = execSync('git remote get-url --push origin', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n // Normalize SSH format (git@github.com:user/repo.git) to HTTPS\n if (url.startsWith('git@')) {\n return url.replace(/^git@([^:]+):/, 'https://$1/').replace(/\\.git$/, '');\n }\n\n // Remove .git suffix from HTTPS URLs\n return url.replace(/\\.git$/, '');\n } catch {\n return '';\n }\n}\n\nconst DEFAULT_PROMPT = `You are a changelog generator. Your task is to analyze git commits and staged changes to generate changelog entries following the Keep a Changelog format.\n\nOutput Format:\nReturn ONLY a JSON object with the following structure:\n{\n \"sections\": [\n {\n \"type\": \"Added\" | \"Changed\" | \"Deprecated\" | \"Removed\" | \"Fixed\" | \"Security\",\n \"items\": [\"description (by Author, YYYY-MM-DD HH:MM, hash)\", \"description 2 (by Author, YYYY-MM-DD HH:MM, hash)\"]\n }\n ]\n}\n\nGuidelines:\n- Use present tense (e.g., \"Add feature\" not \"Added feature\")\n- Be concise but descriptive\n- Group related changes together\n- Focus on user-facing changes\n- Ignore merge commits and trivial changes\n- IMPORTANT: Each item MUST include author, datetime, and commit hash from the input in the format: \"description (by Author, YYYY-MM-DD HH:MM, hash)\"\n- If multiple commits contribute to the same change, list them: \"description (by Author1, datetime1, hash1; Author2, datetime2, hash2)\"\n- Parse conventional commits (feat:, fix:, etc.) into appropriate sections:\n - feat: -> Added\n - fix: -> Fixed\n - docs:, style:, refactor:, perf:, test:, chore: -> Changed\n - BREAKING CHANGE: -> Changed (mention breaking)\n - deprecate: -> Deprecated\n - remove: -> Removed\n - security: -> Security`;\n\nconst DEFAULT_CONFIG: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-sonnet-4.5',\n token: '${OPENROUTER_API_KEY}',\n prompt: DEFAULT_PROMPT,\n },\n changelog: {\n file: 'CHANGELOG.md',\n jsonFile: 'changelog.json',\n format: 'keepachangelog',\n includeDate: true,\n includeTime: true,\n includeAuthor: true,\n includeCommitLink: true,\n repoUrl: '',\n groupBy: 'type',\n },\n git: {\n baseBranch: 'main',\n analyzeDepth: 50,\n },\n};\n\n/**\n * Resolve environment variables in config values\n * Supports ${ENV_VAR} syntax\n */\nfunction resolveEnvVars(value: string): string {\n return value.replace(/\\$\\{([^}]+)\\}/g, (_, envVar) => {\n const envValue = process.env[envVar];\n if (!envValue) {\n throw new Error(`Environment variable ${envVar} is not set`);\n }\n return envValue;\n });\n}\n\n/**\n * Recursively resolve env vars in object\n */\nfunction resolveConfigEnvVars<T>(obj: T): T {\n if (typeof obj === 'string') {\n return resolveEnvVars(obj) as T;\n }\n if (Array.isArray(obj)) {\n return obj.map(resolveConfigEnvVars) as T;\n }\n if (obj && typeof obj === 'object') {\n const resolved: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n resolved[key] = resolveConfigEnvVars(value);\n }\n return resolved as T;\n }\n return obj;\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge(target: Config, source: Partial<Config>): Config {\n return {\n ai: { ...target.ai, ...source.ai },\n changelog: { ...target.changelog, ...source.changelog },\n git: { ...target.git, ...source.git },\n };\n}\n\n/**\n * Load configuration from yaml file\n */\nexport function loadConfig(configPath?: string): Config {\n const defaultPaths = ['tst-changelog.yaml', 'tst-changelog.yml', '.tst-changelog.yaml'];\n\n let filePath: string | undefined;\n\n if (configPath) {\n filePath = resolve(process.cwd(), configPath);\n if (!existsSync(filePath)) {\n throw new Error(`Config file not found: ${filePath}`);\n }\n } else {\n for (const p of defaultPaths) {\n const fullPath = resolve(process.cwd(), p);\n if (existsSync(fullPath)) {\n filePath = fullPath;\n break;\n }\n }\n }\n\n if (!filePath) {\n const config = resolveConfigEnvVars(DEFAULT_CONFIG);\n // Auto-detect repoUrl from git if not configured\n if (!config.changelog.repoUrl) {\n config.changelog.repoUrl = getRepoUrlFromGit();\n }\n return config;\n }\n\n const content = readFileSync(filePath, 'utf-8');\n const parsed = parse(content) as Partial<Config>;\n\n const merged = deepMerge(DEFAULT_CONFIG, parsed);\n const config = resolveConfigEnvVars(merged);\n\n // Auto-detect repoUrl from git if not configured\n if (!config.changelog.repoUrl) {\n config.changelog.repoUrl = getRepoUrlFromGit();\n }\n\n return config;\n}\n\nexport interface InitResult {\n configPath: string;\n huskyConfigured: boolean;\n huskyHook?: string;\n}\n\n/**\n * Initialize a new config file with defaults\n */\nexport function initConfig(fileName = 'tst-changelog.yaml'): InitResult {\n const filePath = resolve(process.cwd(), fileName);\n\n if (existsSync(filePath)) {\n throw new Error(`Config file already exists: ${filePath}`);\n }\n\n // Auto-detect repoUrl from git remote\n const detectedRepoUrl = getRepoUrlFromGit();\n\n const configTemplate: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-sonnet-4.5',\n token: '${OPENROUTER_API_KEY}',\n prompt: DEFAULT_PROMPT,\n },\n changelog: {\n file: 'CHANGELOG.md',\n jsonFile: 'changelog.json',\n format: 'keepachangelog',\n includeDate: true,\n includeTime: true,\n includeAuthor: true,\n includeCommitLink: true,\n repoUrl: detectedRepoUrl,\n groupBy: 'type',\n },\n git: {\n baseBranch: 'main',\n analyzeDepth: 50,\n },\n };\n\n const content = stringify(configTemplate, { lineWidth: 0 });\n writeFileSync(filePath, content, 'utf-8');\n\n // Check for husky and configure hook\n const huskyResult = configureHusky();\n\n return {\n configPath: filePath,\n ...huskyResult,\n };\n}\n\n/**\n * Configure husky pre-commit hook if husky is present\n */\nfunction configureHusky(): { huskyConfigured: boolean; huskyHook?: string } {\n const huskyDir = resolve(process.cwd(), '.husky');\n\n if (!existsSync(huskyDir)) {\n return { huskyConfigured: false };\n }\n\n const preCommitPath = resolve(huskyDir, 'pre-commit');\n const commands = `npx tst-changelog generate\ngit add CHANGELOG.md changelog.json 2>/dev/null || true`;\n\n // Check if hook already exists\n if (existsSync(preCommitPath)) {\n const content = readFileSync(preCommitPath, 'utf-8');\n if (content.includes('tst-changelog')) {\n return { huskyConfigured: false }; // Already configured\n }\n // Append to existing hook\n appendFileSync(preCommitPath, `\\n${commands}\\n`);\n } else {\n // Create new hook\n writeFileSync(preCommitPath, `#!/usr/bin/env sh\\n. \"$(dirname -- \"$0\")/_/husky.sh\"\\n\\n${commands}\\n`, { mode: 0o755 });\n }\n\n return { huskyConfigured: true, huskyHook: preCommitPath };\n}\n","import simpleGit, { SimpleGit } from 'simple-git';\nimport type { CommitInfo, StagedChanges, GitConfig } from './types.js';\n\nexport class GitService {\n private git: SimpleGit;\n private config: GitConfig;\n\n constructor(config: GitConfig, cwd?: string) {\n this.git = simpleGit(cwd);\n this.config = config;\n }\n\n /**\n * Get list of staged files\n */\n async getStagedFiles(): Promise<string[]> {\n const status = await this.git.status();\n return status.staged;\n }\n\n /**\n * Get diff of staged changes\n */\n async getStagedDiff(): Promise<string> {\n const diff = await this.git.diff(['--cached']);\n return diff;\n }\n\n /**\n * Get staged changes (files + diff)\n */\n async getStagedChanges(): Promise<StagedChanges> {\n const [files, diff] = await Promise.all([\n this.getStagedFiles(),\n this.getStagedDiff(),\n ]);\n return { files, diff };\n }\n\n /**\n * Get recent commits from the base branch\n */\n async getRecentCommits(count?: number): Promise<CommitInfo[]> {\n const limit = count ?? this.config.analyzeDepth;\n const log = await this.git.log({\n maxCount: limit,\n format: {\n hash: '%H',\n message: '%s',\n author: '%an',\n date: '%aI',\n body: '%b',\n },\n });\n\n return log.all.map((commit) => ({\n hash: commit.hash,\n message: commit.message,\n author: commit.author,\n date: commit.date,\n body: commit.body?.trim() || undefined,\n }));\n }\n\n /**\n * Get commits not yet in base branch (for feature branches)\n */\n async getUnmergedCommits(): Promise<CommitInfo[]> {\n try {\n const log = await this.git.log({\n from: this.config.baseBranch,\n to: 'HEAD',\n format: {\n hash: '%H',\n message: '%s',\n author: '%an',\n date: '%aI',\n body: '%b',\n },\n });\n\n return log.all.map((commit) => ({\n hash: commit.hash,\n message: commit.message,\n author: commit.author,\n date: commit.date,\n body: commit.body?.trim() || undefined,\n }));\n } catch {\n // If base branch doesn't exist, return empty\n return [];\n }\n }\n\n /**\n * Get current branch name\n */\n async getCurrentBranch(): Promise<string> {\n const branch = await this.git.revparse(['--abbrev-ref', 'HEAD']);\n return branch.trim();\n }\n\n /**\n * Stage a file\n */\n async stageFile(filePath: string): Promise<void> {\n await this.git.add(filePath);\n }\n\n /**\n * Check if we're in a git repository\n */\n async isGitRepo(): Promise<boolean> {\n try {\n await this.git.revparse(['--git-dir']);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get current git user name\n */\n async getCurrentUser(): Promise<string> {\n try {\n const name = await this.git.getConfig('user.name');\n return name.value ?? '';\n } catch {\n return '';\n }\n }\n\n /**\n * Get HEAD commit hash\n */\n async getHeadCommit(): Promise<string> {\n try {\n const hash = await this.git.revparse(['HEAD']);\n return hash.trim();\n } catch {\n return '';\n }\n }\n}\n","import type { AIConfig, CommitInfo, StagedChanges, GeneratedChangelog, ChangelogSection, ChangeType } from './types.js';\n\nconst OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';\n\ninterface OpenRouterResponse {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n}\n\nexport class AIService {\n private config: AIConfig;\n\n constructor(config: AIConfig) {\n this.config = config;\n }\n\n /**\n * Generate changelog entries from commits and staged changes\n */\n async generateChangelog(\n commits: CommitInfo[],\n staged: StagedChanges\n ): Promise<GeneratedChangelog> {\n const userPrompt = this.buildPrompt(commits, staged);\n const response = await this.callOpenRouter(userPrompt);\n return this.parseResponse(response);\n }\n\n private buildPrompt(commits: CommitInfo[], staged: StagedChanges): string {\n const parts: string[] = [];\n\n if (commits.length > 0) {\n parts.push('## Recent Commits:');\n for (const commit of commits) {\n const shortHash = commit.hash.slice(0, 7);\n const [date, timePart] = commit.date.split('T');\n const time = timePart?.slice(0, 5) ?? ''; // HH:MM\n const datetime = time ? `${date} ${time}` : date;\n parts.push(`- [${shortHash}] (${commit.author}, ${datetime}) ${commit.message}`);\n if (commit.body) {\n parts.push(` ${commit.body}`);\n }\n }\n }\n\n if (staged.files.length > 0) {\n parts.push('\\n## Staged Files:');\n parts.push(staged.files.join('\\n'));\n }\n\n if (staged.diff) {\n // Limit diff size to avoid token limits\n const maxDiffLength = 4000;\n const truncatedDiff = staged.diff.length > maxDiffLength\n ? staged.diff.slice(0, maxDiffLength) + '\\n... (truncated)'\n : staged.diff;\n parts.push('\\n## Staged Diff:');\n parts.push('```diff');\n parts.push(truncatedDiff);\n parts.push('```');\n }\n\n parts.push('\\nGenerate changelog entries for these changes.');\n\n return parts.join('\\n');\n }\n\n private async callOpenRouter(prompt: string): Promise<string> {\n const response = await fetch(OPENROUTER_API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.token}`,\n 'HTTP-Referer': 'https://github.com/testudosrl/tst-libs',\n 'X-Title': 'tst-changelog',\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: [\n { role: 'system', content: this.config.prompt ?? '' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.3,\n max_tokens: 4000,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenRouter API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as OpenRouterResponse;\n return data.choices[0]?.message?.content ?? '';\n }\n\n private parseResponse(response: string): GeneratedChangelog {\n try {\n // Extract JSON from response (handle markdown code blocks or raw JSON)\n let jsonStr = response;\n\n // Try markdown code block first\n const codeBlockMatch = response.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (codeBlockMatch) {\n jsonStr = codeBlockMatch[1];\n } else {\n // Try to find JSON object in the response\n const jsonObjectMatch = response.match(/\\{[\\s\\S]*\"sections\"[\\s\\S]*\\}/);\n if (jsonObjectMatch) {\n jsonStr = jsonObjectMatch[0];\n }\n }\n\n const parsed = JSON.parse(jsonStr.trim()) as { sections: ChangelogSection[] };\n\n // Validate and normalize sections\n const validTypes: ChangeType[] = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'];\n const sections = parsed.sections\n .filter((s) => validTypes.includes(s.type))\n .map((s) => ({\n type: s.type,\n items: Array.isArray(s.items) ? s.items.filter((i) => typeof i === 'string') : [],\n }))\n .filter((s) => s.items.length > 0);\n\n return {\n raw: response,\n sections,\n };\n } catch (error) {\n console.error('Failed to parse AI response:', error);\n console.error('Raw response:', response);\n return {\n raw: response,\n sections: [],\n };\n }\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { ChangelogConfig, ChangelogSection, GeneratedChangelog, ChangelogMetadata, ChangelogJson, ChangelogJsonRelease, VersionedEntry } from './types.js';\n\nconst KEEPACHANGELOG_HEADER = `# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n`;\n\nconst SECTION_ORDER = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'] as const;\n\nexport class ChangelogService {\n private config: ChangelogConfig;\n private filePath: string;\n\n constructor(config: ChangelogConfig, cwd?: string) {\n this.config = config;\n this.filePath = resolve(cwd ?? process.cwd(), config.file);\n }\n\n /**\n * Read existing changelog content\n */\n read(): string | null {\n if (!existsSync(this.filePath)) {\n return null;\n }\n return readFileSync(this.filePath, 'utf-8');\n }\n\n /**\n * Generate new changelog entry\n */\n formatEntry(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): string {\n const versionStr = version ?? 'Unreleased';\n const headerParts: string[] = [`## [${versionStr}]`];\n\n // Date and time\n if (this.config.includeDate) {\n const now = metadata?.timestamp ?? new Date();\n let dateStr = now.toISOString().split('T')[0];\n if (this.config.includeTime) {\n const timeStr = now.toTimeString().split(' ')[0].slice(0, 5); // HH:MM\n dateStr += ` ${timeStr}`;\n }\n headerParts.push(`- ${dateStr}`);\n }\n\n // Author\n if (this.config.includeAuthor && metadata?.author) {\n headerParts.push(`by ${metadata.author}`);\n }\n\n // Commit link\n if (this.config.includeCommitLink && metadata?.commitHash) {\n const shortHash = metadata.commitHash.slice(0, 7);\n if (this.config.repoUrl) {\n const commitUrl = `${this.config.repoUrl.replace(/\\/$/, '')}/commit/${metadata.commitHash}`;\n headerParts.push(`([${shortHash}](${commitUrl}))`);\n } else {\n headerParts.push(`(${shortHash})`);\n }\n }\n\n const headerLine = headerParts.join(' ');\n\n const sections = this.sortSections(generated.sections);\n const sectionLines = sections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n /**\n * Format a simple entry with just version and date (no time, no author)\n * Used for --from-commits mode with date grouping\n */\n formatSimpleEntry(generated: GeneratedChangelog, version: string, date: string): string {\n const headerLine = `## [${version}] - ${date}`;\n\n const sections = this.sortSections(generated.sections);\n const sectionLines = sections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n /**\n * Format multiple versioned entries into changelog format\n * Entries should already be sorted (newest first)\n */\n formatMultipleEntries(entries: VersionedEntry[]): string {\n return entries\n .map((entry) => this.formatSimpleEntry(entry.generated, entry.version, entry.date))\n .join('\\n\\n');\n }\n\n /**\n * Update changelog with multiple versioned entries (for --from-commits mode)\n * Entries should be in order from newest to oldest (for display order)\n */\n updateWithMultipleEntries(entries: VersionedEntry[]): string {\n const existing = this.read();\n const newContent = this.formatMultipleEntries(entries);\n\n if (!existing) {\n // Create new changelog\n return KEEPACHANGELOG_HEADER + newContent + '\\n';\n }\n\n // Find where to insert new entries (after header, before first version)\n const lines = existing.split('\\n');\n let insertIndex = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith('## [')) {\n insertIndex = i;\n break;\n }\n }\n\n if (insertIndex === -1) {\n // No version sections found, append after header\n return existing.trimEnd() + '\\n\\n' + newContent + '\\n';\n }\n\n // Insert before first version\n const before = lines.slice(0, insertIndex).join('\\n');\n const after = lines.slice(insertIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newContent + '\\n\\n' + after;\n }\n\n /**\n * Update JSON changelog with multiple releases (for --from-commits mode)\n * Entries should be in order from newest to oldest\n */\n updateJsonWithMultipleEntries(entries: VersionedEntry[]): ChangelogJson {\n const existing = this.readJson();\n\n const newReleases: ChangelogJsonRelease[] = entries.map((entry) => {\n const sections: Record<string, string[]> = {};\n for (const section of entry.generated.sections) {\n sections[section.type] = section.items;\n }\n return {\n version: entry.version,\n date: entry.date,\n sections,\n };\n });\n\n if (!existing) {\n return { releases: newReleases };\n }\n\n // Prepend new releases\n return { releases: [...newReleases, ...existing.releases] };\n }\n\n private sortSections(sections: ChangelogSection[]): ChangelogSection[] {\n return [...sections].sort((a, b) => {\n const indexA = SECTION_ORDER.indexOf(a.type as typeof SECTION_ORDER[number]);\n const indexB = SECTION_ORDER.indexOf(b.type as typeof SECTION_ORDER[number]);\n return indexA - indexB;\n });\n }\n\n private formatSection(section: ChangelogSection): string {\n const items = section.items.map((item) => `- ${this.formatItemWithLinks(item)}`).join('\\n');\n return `### ${section.type}\\n\\n${items}`;\n }\n\n /**\n * Convert commit hashes in item to markdown links if repoUrl is configured\n */\n private formatItemWithLinks(item: string): string {\n if (!this.config.repoUrl) return item;\n\n const repoUrl = this.config.repoUrl.replace(/\\/$/, '');\n\n // Match patterns like \"abc1234\" or \"abc1234; def5678\" at the end of parentheses\n // Pattern: 7-char hex hash\n return item.replace(/\\b([a-f0-9]{7})\\b/g, (match) => {\n return `[${match}](${repoUrl}/commit/${match})`;\n });\n }\n\n /**\n * Update or create changelog with new entry\n */\n update(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): string {\n const existing = this.read();\n\n if (!existing) {\n // Create new changelog\n const newEntry = this.formatEntry(generated, version, metadata);\n return KEEPACHANGELOG_HEADER + newEntry + '\\n';\n }\n\n // Find where to insert new entry (after header, before first version)\n const lines = existing.split('\\n');\n let insertIndex = -1;\n\n // Look for ## [Unreleased] or first ## [ section\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith('## [Unreleased]')) {\n // Merge with existing unreleased section\n const endIndex = this.findSectionEnd(lines, i + 1);\n const existingSectionLines = lines.slice(i, endIndex);\n const mergedSection = this.mergeUnreleasedSection(existingSectionLines, generated, metadata);\n const before = lines.slice(0, i).join('\\n');\n const after = lines.slice(endIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + mergedSection + '\\n' + after;\n }\n if (line.startsWith('## [') && insertIndex === -1) {\n insertIndex = i;\n break;\n }\n }\n\n const newEntry = this.formatEntry(generated, version, metadata);\n\n if (insertIndex === -1) {\n // No version sections found, append after header\n return existing.trimEnd() + '\\n\\n' + newEntry + '\\n';\n }\n\n // Insert before first version\n const before = lines.slice(0, insertIndex).join('\\n');\n const after = lines.slice(insertIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newEntry + '\\n\\n' + after;\n }\n\n /**\n * Merge new entries into existing Unreleased section\n */\n private mergeUnreleasedSection(\n existingLines: string[],\n generated: GeneratedChangelog,\n metadata?: ChangelogMetadata\n ): string {\n // Parse existing sections\n const existingSections: Map<string, string[]> = new Map();\n let currentSection: string | null = null;\n\n for (const line of existingLines) {\n if (line.startsWith('### ')) {\n currentSection = line.slice(4).trim();\n if (!existingSections.has(currentSection)) {\n existingSections.set(currentSection, []);\n }\n } else if (currentSection && line.startsWith('- ')) {\n existingSections.get(currentSection)!.push(line.slice(2));\n }\n }\n\n // Merge new sections\n for (const section of generated.sections) {\n const existing = existingSections.get(section.type) ?? [];\n // Add new items that don't already exist\n for (const item of section.items) {\n if (!existing.includes(item)) {\n existing.push(item);\n }\n }\n existingSections.set(section.type, existing);\n }\n\n // Build merged entry\n const versionStr = 'Unreleased';\n const headerParts: string[] = [`## [${versionStr}]`];\n\n if (this.config.includeDate) {\n const now = metadata?.timestamp ?? new Date();\n let dateStr = now.toISOString().split('T')[0];\n if (this.config.includeTime) {\n const timeStr = now.toTimeString().split(' ')[0].slice(0, 5);\n dateStr += ` ${timeStr}`;\n }\n headerParts.push(`- ${dateStr}`);\n }\n\n if (this.config.includeAuthor && metadata?.author) {\n headerParts.push(`by ${metadata.author}`);\n }\n\n if (this.config.includeCommitLink && metadata?.commitHash) {\n const shortHash = metadata.commitHash.slice(0, 7);\n if (this.config.repoUrl) {\n const commitUrl = `${this.config.repoUrl.replace(/\\/$/, '')}/commit/${metadata.commitHash}`;\n headerParts.push(`([${shortHash}](${commitUrl}))`);\n } else {\n headerParts.push(`(${shortHash})`);\n }\n }\n\n const headerLine = headerParts.join(' ');\n\n // Sort and format sections\n const sortedSections: ChangelogSection[] = [];\n for (const type of SECTION_ORDER) {\n const items = existingSections.get(type);\n if (items && items.length > 0) {\n sortedSections.push({ type, items });\n }\n }\n\n const sectionLines = sortedSections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n private findSectionEnd(lines: string[], startIndex: number): number {\n for (let i = startIndex; i < lines.length; i++) {\n if (lines[i].startsWith('## [')) {\n return i;\n }\n }\n return lines.length;\n }\n\n /**\n * Write changelog to file\n */\n write(content: string): void {\n writeFileSync(this.filePath, content, 'utf-8');\n }\n\n /**\n * Get the file path\n */\n getFilePath(): string {\n return this.filePath;\n }\n\n /**\n * Get JSON file path if configured\n */\n getJsonFilePath(): string | null {\n if (!this.config.jsonFile) return null;\n return resolve(process.cwd(), this.config.jsonFile);\n }\n\n /**\n * Read existing JSON changelog\n */\n readJson(): ChangelogJson | null {\n const jsonPath = this.getJsonFilePath();\n if (!jsonPath || !existsSync(jsonPath)) {\n return null;\n }\n try {\n const content = readFileSync(jsonPath, 'utf-8');\n return JSON.parse(content) as ChangelogJson;\n } catch {\n return null;\n }\n }\n\n /**\n * Create a JSON release entry from generated changelog\n */\n createJsonRelease(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): ChangelogJsonRelease {\n const now = metadata?.timestamp ?? new Date();\n const sections: Record<string, string[]> = {};\n\n for (const section of generated.sections) {\n sections[section.type] = section.items;\n }\n\n const release: ChangelogJsonRelease = {\n version: version ?? 'Unreleased',\n date: now.toISOString().split('T')[0],\n sections,\n };\n\n if (this.config.includeTime) {\n release.time = now.toTimeString().split(' ')[0].slice(0, 5);\n }\n\n if (this.config.includeAuthor && metadata?.author) {\n release.author = metadata.author;\n }\n\n if (this.config.includeCommitLink && metadata?.commitHash) {\n release.commitHash = metadata.commitHash;\n }\n\n return release;\n }\n\n /**\n * Update JSON changelog with new release\n */\n updateJson(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): ChangelogJson {\n const newRelease = this.createJsonRelease(generated, version, metadata);\n const existing = this.readJson();\n\n if (!existing) {\n return { releases: [newRelease] };\n }\n\n // Find and merge or prepend\n const unreleasedIndex = existing.releases.findIndex(r => r.version === 'Unreleased');\n\n if (unreleasedIndex >= 0 && newRelease.version === 'Unreleased') {\n // Merge with existing unreleased\n const existingRelease = existing.releases[unreleasedIndex];\n for (const [type, items] of Object.entries(newRelease.sections)) {\n const existingItems = existingRelease.sections[type] ?? [];\n for (const item of items) {\n if (!existingItems.includes(item)) {\n existingItems.push(item);\n }\n }\n existingRelease.sections[type] = existingItems;\n }\n // Update metadata to latest\n existingRelease.date = newRelease.date;\n if (newRelease.time) existingRelease.time = newRelease.time;\n if (newRelease.author) existingRelease.author = newRelease.author;\n if (newRelease.commitHash) existingRelease.commitHash = newRelease.commitHash;\n } else {\n // Prepend new release\n existing.releases.unshift(newRelease);\n }\n\n return existing;\n }\n\n /**\n * Write JSON changelog to file\n */\n writeJson(data: ChangelogJson): void {\n const jsonPath = this.getJsonFilePath();\n if (!jsonPath) return;\n writeFileSync(jsonPath, JSON.stringify(data, null, 2), 'utf-8');\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","resolve","config","readFileSync","writeFileSync","existsSync","resolve","newEntry","before","after","readFileSync","resolve","existsSync"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/git.ts","../src/ai.ts","../src/changelog.ts"],"sourcesContent":["import 'dotenv/config';\nimport { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, resolve } from 'node:path';\nimport { loadConfig, initConfig } from './config.js';\nimport { GitService } from './git.js';\nimport { AIService } from './ai.js';\nimport { ChangelogService } from './changelog.js';\nimport type { CLIOptions, ChangelogMetadata, CommitInfo, DateGroupedCommits, VersionedEntry } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));\n\n/**\n * Parse a semver version string and return major, minor, patch\n */\nfunction parseVersion(version: string): { major: number; minor: number; patch: number } | null {\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match) return null;\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n };\n}\n\n/**\n * Get the latest version from changelog.json\n * Returns the highest semver version found, or null if no valid versions\n */\nfunction getLatestVersionFromChangelog(jsonFilePath?: string): string | null {\n const changelogPath = jsonFilePath ?? resolve(process.cwd(), 'changelog.json');\n\n if (!existsSync(changelogPath)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(changelogPath, 'utf-8'));\n if (!data.releases || !Array.isArray(data.releases)) {\n return null;\n }\n\n let latestVersion: string | null = null;\n let latestParsed: { major: number; minor: number; patch: number } | null = null;\n\n for (const release of data.releases) {\n if (!release.version || release.version === 'Unreleased') continue;\n\n const parsed = parseVersion(release.version);\n if (!parsed) continue;\n\n if (!latestParsed ||\n parsed.major > latestParsed.major ||\n (parsed.major === latestParsed.major && parsed.minor > latestParsed.minor) ||\n (parsed.major === latestParsed.major && parsed.minor === latestParsed.minor && parsed.patch > latestParsed.patch)) {\n latestVersion = release.version;\n latestParsed = parsed;\n }\n }\n\n return latestVersion;\n } catch {\n return null;\n }\n}\n\n/**\n * Get version from package.json\n */\nfunction getVersionFromPackageJson(): { major: number; minor: number; patch: number } | null {\n const pkgPath = resolve(process.cwd(), 'package.json');\n\n if (!existsSync(pkgPath)) {\n return null;\n }\n\n try {\n const projectPkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n const currentVersion = projectPkg.version ?? '0.0.0';\n return parseVersion(currentVersion);\n } catch {\n return null;\n }\n}\n\n/**\n * Compare two versions and return the higher one\n */\nfunction getHigherVersion(\n a: { major: number; minor: number; patch: number } | null,\n b: { major: number; minor: number; patch: number } | null\n): { major: number; minor: number; patch: number } | null {\n if (!a) return b;\n if (!b) return a;\n\n if (a.major > b.major) return a;\n if (b.major > a.major) return b;\n if (a.minor > b.minor) return a;\n if (b.minor > a.minor) return b;\n if (a.patch > b.patch) return a;\n return b;\n}\n\n/**\n * Get the next minor version by comparing changelog.json and package.json\n * Uses the higher version as base, then increments minor\n */\nfunction getNextMinorVersion(jsonFilePath?: string): string {\n // Get version from changelog.json\n const latestFromChangelog = getLatestVersionFromChangelog(jsonFilePath);\n const changelogVersion = latestFromChangelog ? parseVersion(latestFromChangelog) : null;\n\n // Get version from package.json\n const pkgVersion = getVersionFromPackageJson();\n\n // Use the higher version as base\n const baseVersion = getHigherVersion(changelogVersion, pkgVersion);\n\n if (baseVersion) {\n return `${baseVersion.major}.${baseVersion.minor + 1}.0`;\n }\n\n return '0.1.0';\n}\n\n/**\n * Get base version for --from-commits mode\n * Compares changelog.json and package.json, uses the higher one\n */\nfunction getBaseVersionForFromCommits(jsonFilePath?: string): { major: number; minor: number } {\n // Get version from changelog.json\n const latestFromChangelog = getLatestVersionFromChangelog(jsonFilePath);\n const changelogVersion = latestFromChangelog ? parseVersion(latestFromChangelog) : null;\n\n // Get version from package.json\n const pkgVersion = getVersionFromPackageJson();\n\n // Use the higher version as base\n const baseVersion = getHigherVersion(changelogVersion, pkgVersion);\n\n if (baseVersion) {\n return { major: baseVersion.major, minor: baseVersion.minor };\n }\n\n return { major: 0, minor: 0 };\n}\n\n/**\n * Increment minor version from base by a given count\n * e.g., base {major: 0, minor: 5}, count 1 => \"0.6.0\"\n * base {major: 0, minor: 5}, count 3 => \"0.8.0\"\n */\nfunction incrementMinorVersion(base: { major: number; minor: number }, count: number): string {\n return `${base.major}.${base.minor + count}.0`;\n}\n\n/**\n * Group commits by their date (YYYY-MM-DD)\n */\nfunction groupCommitsByDate(commits: CommitInfo[]): DateGroupedCommits {\n const grouped: DateGroupedCommits = new Map();\n\n for (const commit of commits) {\n // Extract date part (YYYY-MM-DD) from ISO date string\n const date = commit.date.split('T')[0];\n\n if (!grouped.has(date)) {\n grouped.set(date, []);\n }\n grouped.get(date)!.push(commit);\n }\n\n return grouped;\n}\n\nconst program = new Command();\n\nprogram\n .name('tst-changelog')\n .description('AI-powered changelog generator using OpenRouter')\n .version(pkg.version);\n\nprogram\n .command('init')\n .description('Create a default configuration file')\n .option('-f, --file <name>', 'Config file name', 'tst-changelog.yaml')\n .action((options: { file: string }) => {\n try {\n const result = initConfig(options.file);\n console.log(`Created config file: ${result.configPath}`);\n\n if (result.huskyConfigured) {\n console.log(`Configured husky hook: ${result.huskyHook}`);\n }\n\n console.log('\\nNext steps:');\n console.log('1. Set the OPENROUTER_API_KEY environment variable');\n console.log('2. Adjust settings in the config file as needed');\n if (!result.huskyConfigured) {\n console.log('3. Run: npx tst-changelog generate');\n }\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('generate', { isDefault: true })\n .description('Generate changelog from staged changes or commit history')\n .option('-c, --config <path>', 'Path to config file')\n .option('-d, --dry-run', 'Preview without modifying files')\n .option('-v, --verbose', 'Enable verbose output')\n .option('--from-commits <count>', 'Generate from last N commits instead of staged changes', parseInt)\n .option('--version <version>', 'Version label for the changelog entry (default: \"Unreleased\" or date for --from-commits)')\n .action(run);\n\nasync function run(options: CLIOptions): Promise<void> {\n const verbose = options.verbose ?? false;\n\n try {\n // Load configuration\n if (verbose) console.log('Loading configuration...');\n const config = loadConfig(options.config);\n if (verbose) console.log('Config loaded:', JSON.stringify(config, null, 2));\n\n // Initialize services\n const git = new GitService(config.git);\n const ai = new AIService(config.ai);\n const changelog = new ChangelogService(config.changelog);\n\n // Check if we're in a git repo\n if (!(await git.isGitRepo())) {\n console.error('Error: Not a git repository');\n process.exit(1);\n }\n\n if (options.fromCommits) {\n // === FROM COMMITS MODE: Group by date, generate per-date entries ===\n if (verbose) console.log(`Getting last ${options.fromCommits} commits...`);\n const commits = await git.getRecentCommits(options.fromCommits);\n\n if (commits.length === 0) {\n console.log('No commits found.');\n process.exit(0);\n }\n\n if (verbose) console.log(`Found ${commits.length} commits`);\n\n // Group commits by date\n const groupedByDate = groupCommitsByDate(commits);\n const sortedDates = [...groupedByDate.keys()].sort(); // ascending (oldest first)\n\n if (verbose) {\n console.log(`Grouped into ${sortedDates.length} date(s):`);\n for (const date of sortedDates) {\n const dateCommits = groupedByDate.get(date)!;\n console.log(` ${date}: ${dateCommits.length} commit(s)`);\n }\n }\n\n // Get base version from changelog.json (or package.json as fallback)\n const baseVersion = getBaseVersionForFromCommits(changelog.getJsonFilePath() ?? undefined);\n if (verbose) console.log(`Base version: ${baseVersion.major}.${baseVersion.minor}.0`);\n\n // Generate changelog entries for each date (oldest to newest)\n const entries: VersionedEntry[] = [];\n const emptyStaged = { files: [], diff: '' };\n\n for (let i = 0; i < sortedDates.length; i++) {\n const date = sortedDates[i];\n const dateCommits = groupedByDate.get(date)!;\n const version = incrementMinorVersion(baseVersion, i + 1);\n\n if (verbose) console.log(`\\nGenerating changelog for ${date} (${version})...`);\n console.log(`Generating changelog for ${date}...`);\n\n const generated = await ai.generateChangelog(dateCommits, emptyStaged);\n\n if (generated.sections.length === 0) {\n if (verbose) console.log(` No entries generated for ${date}, skipping.`);\n continue;\n }\n\n if (verbose) {\n console.log(` Generated sections for ${date}:`);\n for (const section of generated.sections) {\n console.log(` ${section.type}:`);\n for (const item of section.items) {\n console.log(` - ${item}`);\n }\n }\n }\n\n entries.push({ version, date, generated });\n }\n\n if (entries.length === 0) {\n console.log('No changelog entries generated.');\n process.exit(0);\n }\n\n // Reverse for changelog (newest first)\n entries.reverse();\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n if (changelog.getJsonFilePath()) {\n console.log('Would update JSON at:', changelog.getJsonFilePath());\n }\n console.log(`\\n--- ${entries.length} new entries (newest first) ---\\n`);\n console.log(changelog.formatMultipleEntries(entries));\n console.log('\\n--- JSON releases ---');\n for (const entry of entries) {\n console.log(JSON.stringify({ version: entry.version, date: entry.date }, null, 2));\n }\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Update changelog (MD) with multiple entries\n const newContent = changelog.updateWithMultipleEntries(entries);\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n // Update changelog (JSON) with multiple entries\n if (changelog.getJsonFilePath()) {\n const jsonData = changelog.updateJsonWithMultipleEntries(entries);\n changelog.writeJson(jsonData);\n console.log(`Updated: ${changelog.getJsonFilePath()}`);\n }\n\n console.log(`Done! Created ${entries.length} version entries.`);\n\n } else {\n // === STAGED CHANGES MODE: Original behavior ===\n if (verbose) console.log('Getting staged changes...');\n const staged = await git.getStagedChanges();\n\n if (staged.files.length === 0) {\n console.log('No staged changes found. Stage some changes first.');\n process.exit(0);\n }\n\n if (verbose) {\n console.log(`Staged files: ${staged.files.join(', ')}`);\n console.log(`Diff length: ${staged.diff.length} chars`);\n }\n\n // Get recent commits for context\n if (verbose) console.log('Getting recent commits...');\n const commits = await git.getUnmergedCommits();\n if (verbose) console.log(`Found ${commits.length} unmerged commits`);\n\n // Generate changelog using AI\n console.log('Generating changelog with AI...');\n const generated = await ai.generateChangelog(commits, staged);\n\n if (generated.sections.length === 0) {\n console.log('No changelog entries generated.');\n if (verbose) console.log('Raw AI response:', generated.raw);\n process.exit(0);\n }\n\n if (verbose) {\n console.log('Generated sections:');\n for (const section of generated.sections) {\n console.log(` ${section.type}:`);\n for (const item of section.items) {\n console.log(` - ${item}`);\n }\n }\n }\n\n // Collect metadata for changelog entry\n const [author, commitHash] = await Promise.all([\n git.getCurrentUser(),\n git.getHeadCommit(),\n ]);\n const metadata: ChangelogMetadata = {\n author: author || undefined,\n commitHash: commitHash || undefined,\n timestamp: new Date(),\n };\n\n if (verbose) {\n console.log('Metadata:', metadata);\n }\n\n // Determine version label (always use next minor version)\n const version = options.version ?? getNextMinorVersion(changelog.getJsonFilePath() ?? undefined);\n\n // Update changelog (MD)\n const newContent = changelog.update(generated, version, metadata);\n\n // Update changelog (JSON)\n const jsonData = changelog.updateJson(generated, version, metadata);\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n if (changelog.getJsonFilePath()) {\n console.log('Would update JSON at:', changelog.getJsonFilePath());\n }\n console.log('\\n--- New MD entry ---');\n console.log(changelog.formatEntry(generated, version, metadata));\n console.log('\\n--- New JSON entry ---');\n console.log(JSON.stringify(jsonData.releases[0], null, 2));\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Write changelog (MD)\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n // Write changelog (JSON)\n if (changelog.getJsonFilePath()) {\n changelog.writeJson(jsonData);\n console.log(`Updated: ${changelog.getJsonFilePath()}`);\n }\n\n // Auto-stage changelog files\n await git.stageFile(config.changelog.file);\n if (config.changelog.jsonFile) {\n await git.stageFile(config.changelog.jsonFile);\n }\n console.log('Staged changelog files');\n\n console.log('Done!');\n }\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n if (verbose && error instanceof Error) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n}\n\nprogram.parse();\n\n// Export for programmatic usage\nexport { loadConfig, initConfig, type InitResult } from './config.js';\nexport { GitService } from './git.js';\nexport { AIService } from './ai.js';\nexport { ChangelogService } from './changelog.js';\nexport * from './types.js';\n","import { readFileSync, existsSync, writeFileSync, appendFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { parse, stringify } from 'yaml';\nimport type { Config } from './types.js';\n\n/**\n * Get repository URL from git remote origin\n * Normalizes SSH URLs to HTTPS for web links\n */\nfunction getRepoUrlFromGit(): string {\n try {\n const url = execSync('git remote get-url --push origin', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n // Normalize SSH format (git@github.com:user/repo.git) to HTTPS\n if (url.startsWith('git@')) {\n return url.replace(/^git@([^:]+):/, 'https://$1/').replace(/\\.git$/, '');\n }\n\n // Remove .git suffix from HTTPS URLs\n return url.replace(/\\.git$/, '');\n } catch {\n return '';\n }\n}\n\nconst DEFAULT_PROMPT = `You are a changelog generator. Your task is to analyze git commits and staged changes to generate changelog entries following the Keep a Changelog format.\n\nOutput Format:\nReturn ONLY a JSON object with the following structure:\n{\n \"sections\": [\n {\n \"type\": \"Added\" | \"Changed\" | \"Deprecated\" | \"Removed\" | \"Fixed\" | \"Security\",\n \"items\": [\"description (by Author, YYYY-MM-DD HH:MM, hash)\", \"description 2 (by Author, YYYY-MM-DD HH:MM, hash)\"]\n }\n ]\n}\n\nGuidelines:\n- Use present tense (e.g., \"Add feature\" not \"Added feature\")\n- Be concise but descriptive\n- Group related changes together\n- Focus on user-facing changes\n- Ignore merge commits and trivial changes\n- IMPORTANT: Each item MUST include author, datetime, and commit hash from the input in the format: \"description (by Author, YYYY-MM-DD HH:MM, hash)\"\n- If multiple commits contribute to the same change, list them: \"description (by Author1, datetime1, hash1; Author2, datetime2, hash2)\"\n- Parse conventional commits (feat:, fix:, etc.) into appropriate sections:\n - feat: -> Added\n - fix: -> Fixed\n - docs:, style:, refactor:, perf:, test:, chore: -> Changed\n - BREAKING CHANGE: -> Changed (mention breaking)\n - deprecate: -> Deprecated\n - remove: -> Removed\n - security: -> Security`;\n\nconst DEFAULT_CONFIG: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-sonnet-4.5',\n token: '${OPENROUTER_API_KEY}',\n prompt: DEFAULT_PROMPT,\n },\n changelog: {\n file: 'CHANGELOG.md',\n jsonFile: 'changelog.json',\n format: 'keepachangelog',\n includeDate: true,\n includeTime: true,\n includeAuthor: true,\n includeCommitLink: true,\n repoUrl: '',\n groupBy: 'type',\n },\n git: {\n baseBranch: 'main',\n analyzeDepth: 50,\n },\n};\n\n/**\n * Resolve environment variables in config values\n * Supports ${ENV_VAR} syntax\n */\nfunction resolveEnvVars(value: string): string {\n return value.replace(/\\$\\{([^}]+)\\}/g, (_, envVar) => {\n const envValue = process.env[envVar];\n if (!envValue) {\n throw new Error(`Environment variable ${envVar} is not set`);\n }\n return envValue;\n });\n}\n\n/**\n * Recursively resolve env vars in object\n */\nfunction resolveConfigEnvVars<T>(obj: T): T {\n if (typeof obj === 'string') {\n return resolveEnvVars(obj) as T;\n }\n if (Array.isArray(obj)) {\n return obj.map(resolveConfigEnvVars) as T;\n }\n if (obj && typeof obj === 'object') {\n const resolved: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n resolved[key] = resolveConfigEnvVars(value);\n }\n return resolved as T;\n }\n return obj;\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge(target: Config, source: Partial<Config>): Config {\n return {\n ai: { ...target.ai, ...source.ai },\n changelog: { ...target.changelog, ...source.changelog },\n git: { ...target.git, ...source.git },\n };\n}\n\n/**\n * Load configuration from yaml file\n */\nexport function loadConfig(configPath?: string): Config {\n const defaultPaths = ['tst-changelog.yaml', 'tst-changelog.yml', '.tst-changelog.yaml'];\n\n let filePath: string | undefined;\n\n if (configPath) {\n filePath = resolve(process.cwd(), configPath);\n if (!existsSync(filePath)) {\n throw new Error(`Config file not found: ${filePath}`);\n }\n } else {\n for (const p of defaultPaths) {\n const fullPath = resolve(process.cwd(), p);\n if (existsSync(fullPath)) {\n filePath = fullPath;\n break;\n }\n }\n }\n\n if (!filePath) {\n const config = resolveConfigEnvVars(DEFAULT_CONFIG);\n // Auto-detect repoUrl from git if not configured\n if (!config.changelog.repoUrl) {\n config.changelog.repoUrl = getRepoUrlFromGit();\n }\n return config;\n }\n\n const content = readFileSync(filePath, 'utf-8');\n const parsed = parse(content) as Partial<Config>;\n\n const merged = deepMerge(DEFAULT_CONFIG, parsed);\n const config = resolveConfigEnvVars(merged);\n\n // Auto-detect repoUrl from git if not configured\n if (!config.changelog.repoUrl) {\n config.changelog.repoUrl = getRepoUrlFromGit();\n }\n\n return config;\n}\n\nexport interface InitResult {\n configPath: string;\n huskyConfigured: boolean;\n huskyHook?: string;\n}\n\n/**\n * Initialize a new config file with defaults\n */\nexport function initConfig(fileName = 'tst-changelog.yaml'): InitResult {\n const filePath = resolve(process.cwd(), fileName);\n\n if (existsSync(filePath)) {\n throw new Error(`Config file already exists: ${filePath}`);\n }\n\n // Auto-detect repoUrl from git remote\n const detectedRepoUrl = getRepoUrlFromGit();\n\n const configTemplate: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-sonnet-4.5',\n token: '${OPENROUTER_API_KEY}',\n prompt: DEFAULT_PROMPT,\n },\n changelog: {\n file: 'CHANGELOG.md',\n jsonFile: 'changelog.json',\n format: 'keepachangelog',\n includeDate: true,\n includeTime: true,\n includeAuthor: true,\n includeCommitLink: true,\n repoUrl: detectedRepoUrl,\n groupBy: 'type',\n },\n git: {\n baseBranch: 'main',\n analyzeDepth: 50,\n },\n };\n\n const content = stringify(configTemplate, { lineWidth: 0 });\n writeFileSync(filePath, content, 'utf-8');\n\n // Check for husky and configure hook\n const huskyResult = configureHusky();\n\n return {\n configPath: filePath,\n ...huskyResult,\n };\n}\n\n/**\n * Configure husky pre-commit hook if husky is present\n */\nfunction configureHusky(): { huskyConfigured: boolean; huskyHook?: string } {\n const huskyDir = resolve(process.cwd(), '.husky');\n\n if (!existsSync(huskyDir)) {\n return { huskyConfigured: false };\n }\n\n const preCommitPath = resolve(huskyDir, 'pre-commit');\n const commands = `npx tst-changelog generate\ngit add CHANGELOG.md changelog.json 2>/dev/null || true`;\n\n // Check if hook already exists\n if (existsSync(preCommitPath)) {\n const content = readFileSync(preCommitPath, 'utf-8');\n if (content.includes('tst-changelog')) {\n return { huskyConfigured: false }; // Already configured\n }\n // Append to existing hook\n appendFileSync(preCommitPath, `\\n${commands}\\n`);\n } else {\n // Create new hook\n writeFileSync(preCommitPath, `#!/usr/bin/env sh\\n. \"$(dirname -- \"$0\")/_/husky.sh\"\\n\\n${commands}\\n`, { mode: 0o755 });\n }\n\n return { huskyConfigured: true, huskyHook: preCommitPath };\n}\n","import simpleGit, { SimpleGit } from 'simple-git';\nimport type { CommitInfo, StagedChanges, GitConfig } from './types.js';\n\nexport class GitService {\n private git: SimpleGit;\n private config: GitConfig;\n\n constructor(config: GitConfig, cwd?: string) {\n this.git = simpleGit(cwd);\n this.config = config;\n }\n\n /**\n * Get list of staged files\n */\n async getStagedFiles(): Promise<string[]> {\n const status = await this.git.status();\n return status.staged;\n }\n\n /**\n * Get diff of staged changes\n */\n async getStagedDiff(): Promise<string> {\n const diff = await this.git.diff(['--cached']);\n return diff;\n }\n\n /**\n * Get staged changes (files + diff)\n */\n async getStagedChanges(): Promise<StagedChanges> {\n const [files, diff] = await Promise.all([\n this.getStagedFiles(),\n this.getStagedDiff(),\n ]);\n return { files, diff };\n }\n\n /**\n * Get recent commits from the base branch\n */\n async getRecentCommits(count?: number): Promise<CommitInfo[]> {\n const limit = count ?? this.config.analyzeDepth;\n const log = await this.git.log({\n maxCount: limit,\n format: {\n hash: '%H',\n message: '%s',\n author: '%an',\n date: '%aI',\n body: '%b',\n },\n });\n\n return log.all.map((commit) => ({\n hash: commit.hash,\n message: commit.message,\n author: commit.author,\n date: commit.date,\n body: commit.body?.trim() || undefined,\n }));\n }\n\n /**\n * Get commits not yet in base branch (for feature branches)\n */\n async getUnmergedCommits(): Promise<CommitInfo[]> {\n try {\n const log = await this.git.log({\n from: this.config.baseBranch,\n to: 'HEAD',\n format: {\n hash: '%H',\n message: '%s',\n author: '%an',\n date: '%aI',\n body: '%b',\n },\n });\n\n return log.all.map((commit) => ({\n hash: commit.hash,\n message: commit.message,\n author: commit.author,\n date: commit.date,\n body: commit.body?.trim() || undefined,\n }));\n } catch {\n // If base branch doesn't exist, return empty\n return [];\n }\n }\n\n /**\n * Get current branch name\n */\n async getCurrentBranch(): Promise<string> {\n const branch = await this.git.revparse(['--abbrev-ref', 'HEAD']);\n return branch.trim();\n }\n\n /**\n * Stage a file\n */\n async stageFile(filePath: string): Promise<void> {\n await this.git.add(filePath);\n }\n\n /**\n * Check if we're in a git repository\n */\n async isGitRepo(): Promise<boolean> {\n try {\n await this.git.revparse(['--git-dir']);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get current git user name\n */\n async getCurrentUser(): Promise<string> {\n try {\n const name = await this.git.getConfig('user.name');\n return name.value ?? '';\n } catch {\n return '';\n }\n }\n\n /**\n * Get HEAD commit hash\n */\n async getHeadCommit(): Promise<string> {\n try {\n const hash = await this.git.revparse(['HEAD']);\n return hash.trim();\n } catch {\n return '';\n }\n }\n}\n","import type { AIConfig, CommitInfo, StagedChanges, GeneratedChangelog, ChangelogSection, ChangeType } from './types.js';\n\nconst OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';\n\ninterface OpenRouterResponse {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n}\n\nexport class AIService {\n private config: AIConfig;\n\n constructor(config: AIConfig) {\n this.config = config;\n }\n\n /**\n * Generate changelog entries from commits and staged changes\n */\n async generateChangelog(\n commits: CommitInfo[],\n staged: StagedChanges\n ): Promise<GeneratedChangelog> {\n const userPrompt = this.buildPrompt(commits, staged);\n const response = await this.callOpenRouter(userPrompt);\n return this.parseResponse(response);\n }\n\n private buildPrompt(commits: CommitInfo[], staged: StagedChanges): string {\n const parts: string[] = [];\n\n if (commits.length > 0) {\n parts.push('## Recent Commits:');\n for (const commit of commits) {\n const shortHash = commit.hash.slice(0, 7);\n const [date, timePart] = commit.date.split('T');\n const time = timePart?.slice(0, 5) ?? ''; // HH:MM\n const datetime = time ? `${date} ${time}` : date;\n parts.push(`- [${shortHash}] (${commit.author}, ${datetime}) ${commit.message}`);\n if (commit.body) {\n parts.push(` ${commit.body}`);\n }\n }\n }\n\n if (staged.files.length > 0) {\n parts.push('\\n## Staged Files:');\n parts.push(staged.files.join('\\n'));\n }\n\n if (staged.diff) {\n // Limit diff size to avoid token limits\n const maxDiffLength = 4000;\n const truncatedDiff = staged.diff.length > maxDiffLength\n ? staged.diff.slice(0, maxDiffLength) + '\\n... (truncated)'\n : staged.diff;\n parts.push('\\n## Staged Diff:');\n parts.push('```diff');\n parts.push(truncatedDiff);\n parts.push('```');\n }\n\n parts.push('\\nGenerate changelog entries for these changes.');\n\n return parts.join('\\n');\n }\n\n private async callOpenRouter(prompt: string): Promise<string> {\n const response = await fetch(OPENROUTER_API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.token}`,\n 'HTTP-Referer': 'https://github.com/testudosrl/tst-libs',\n 'X-Title': 'tst-changelog',\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: [\n { role: 'system', content: this.config.prompt ?? '' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.3,\n max_tokens: 4000,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenRouter API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as OpenRouterResponse;\n return data.choices[0]?.message?.content ?? '';\n }\n\n private parseResponse(response: string): GeneratedChangelog {\n try {\n // Extract JSON from response (handle markdown code blocks or raw JSON)\n let jsonStr = response;\n\n // Try markdown code block first\n const codeBlockMatch = response.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (codeBlockMatch) {\n jsonStr = codeBlockMatch[1];\n } else {\n // Try to find JSON object in the response\n const jsonObjectMatch = response.match(/\\{[\\s\\S]*\"sections\"[\\s\\S]*\\}/);\n if (jsonObjectMatch) {\n jsonStr = jsonObjectMatch[0];\n }\n }\n\n const parsed = JSON.parse(jsonStr.trim()) as { sections: ChangelogSection[] };\n\n // Validate and normalize sections\n const validTypes: ChangeType[] = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'];\n const sections = parsed.sections\n .filter((s) => validTypes.includes(s.type))\n .map((s) => ({\n type: s.type,\n items: Array.isArray(s.items) ? s.items.filter((i) => typeof i === 'string') : [],\n }))\n .filter((s) => s.items.length > 0);\n\n return {\n raw: response,\n sections,\n };\n } catch (error) {\n console.error('Failed to parse AI response:', error);\n console.error('Raw response:', response);\n return {\n raw: response,\n sections: [],\n };\n }\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { ChangelogConfig, ChangelogSection, GeneratedChangelog, ChangelogMetadata, ChangelogJson, ChangelogJsonRelease, VersionedEntry } from './types.js';\n\nconst KEEPACHANGELOG_HEADER = `# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n`;\n\nconst SECTION_ORDER = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security'] as const;\n\nexport class ChangelogService {\n private config: ChangelogConfig;\n private filePath: string;\n\n constructor(config: ChangelogConfig, cwd?: string) {\n this.config = config;\n this.filePath = resolve(cwd ?? process.cwd(), config.file);\n }\n\n /**\n * Read existing changelog content\n */\n read(): string | null {\n if (!existsSync(this.filePath)) {\n return null;\n }\n return readFileSync(this.filePath, 'utf-8');\n }\n\n /**\n * Generate new changelog entry\n */\n formatEntry(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): string {\n const versionStr = version ?? 'Unreleased';\n const headerParts: string[] = [`## [${versionStr}]`];\n\n // Date and time\n if (this.config.includeDate) {\n const now = metadata?.timestamp ?? new Date();\n let dateStr = now.toISOString().split('T')[0];\n if (this.config.includeTime) {\n const timeStr = now.toTimeString().split(' ')[0].slice(0, 5); // HH:MM\n dateStr += ` ${timeStr}`;\n }\n headerParts.push(`- ${dateStr}`);\n }\n\n // Author\n if (this.config.includeAuthor && metadata?.author) {\n headerParts.push(`by ${metadata.author}`);\n }\n\n // Commit link\n if (this.config.includeCommitLink && metadata?.commitHash) {\n const shortHash = metadata.commitHash.slice(0, 7);\n if (this.config.repoUrl) {\n const commitUrl = `${this.config.repoUrl.replace(/\\/$/, '')}/commit/${metadata.commitHash}`;\n headerParts.push(`([${shortHash}](${commitUrl}))`);\n } else {\n headerParts.push(`(${shortHash})`);\n }\n }\n\n const headerLine = headerParts.join(' ');\n\n const sections = this.sortSections(generated.sections);\n const sectionLines = sections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n /**\n * Format a simple entry with just version and date (no time, no author)\n * Used for --from-commits mode with date grouping\n */\n formatSimpleEntry(generated: GeneratedChangelog, version: string, date: string): string {\n const headerLine = `## [${version}] - ${date}`;\n\n const sections = this.sortSections(generated.sections);\n const sectionLines = sections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n /**\n * Format multiple versioned entries into changelog format\n * Entries should already be sorted (newest first)\n */\n formatMultipleEntries(entries: VersionedEntry[]): string {\n return entries\n .map((entry) => this.formatSimpleEntry(entry.generated, entry.version, entry.date))\n .join('\\n\\n');\n }\n\n /**\n * Update changelog with multiple versioned entries (for --from-commits mode)\n * Entries should be in order from newest to oldest (for display order)\n */\n updateWithMultipleEntries(entries: VersionedEntry[]): string {\n const existing = this.read();\n const newContent = this.formatMultipleEntries(entries);\n\n if (!existing) {\n // Create new changelog\n return KEEPACHANGELOG_HEADER + newContent + '\\n';\n }\n\n // Find where to insert new entries (after header, before first version)\n const lines = existing.split('\\n');\n let insertIndex = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith('## [')) {\n insertIndex = i;\n break;\n }\n }\n\n if (insertIndex === -1) {\n // No version sections found, append after header\n return existing.trimEnd() + '\\n\\n' + newContent + '\\n';\n }\n\n // Insert before first version\n const before = lines.slice(0, insertIndex).join('\\n');\n const after = lines.slice(insertIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newContent + '\\n\\n' + after;\n }\n\n /**\n * Update JSON changelog with multiple releases (for --from-commits mode)\n * Entries should be in order from newest to oldest\n */\n updateJsonWithMultipleEntries(entries: VersionedEntry[]): ChangelogJson {\n const existing = this.readJson();\n\n const newReleases: ChangelogJsonRelease[] = entries.map((entry) => {\n const sections: Record<string, string[]> = {};\n for (const section of entry.generated.sections) {\n sections[section.type] = section.items;\n }\n return {\n version: entry.version,\n date: entry.date,\n sections,\n };\n });\n\n if (!existing) {\n return { releases: newReleases };\n }\n\n // Prepend new releases\n return { releases: [...newReleases, ...existing.releases] };\n }\n\n private sortSections(sections: ChangelogSection[]): ChangelogSection[] {\n return [...sections].sort((a, b) => {\n const indexA = SECTION_ORDER.indexOf(a.type as typeof SECTION_ORDER[number]);\n const indexB = SECTION_ORDER.indexOf(b.type as typeof SECTION_ORDER[number]);\n return indexA - indexB;\n });\n }\n\n private formatSection(section: ChangelogSection): string {\n const items = section.items.map((item) => `- ${this.formatItemWithLinks(item)}`).join('\\n');\n return `### ${section.type}\\n\\n${items}`;\n }\n\n /**\n * Convert commit hashes in item to markdown links if repoUrl is configured\n */\n private formatItemWithLinks(item: string): string {\n if (!this.config.repoUrl) return item;\n\n const repoUrl = this.config.repoUrl.replace(/\\/$/, '');\n\n // Match patterns like \"abc1234\" or \"abc1234; def5678\" at the end of parentheses\n // Pattern: 7-char hex hash\n return item.replace(/\\b([a-f0-9]{7})\\b/g, (match) => {\n return `[${match}](${repoUrl}/commit/${match})`;\n });\n }\n\n /**\n * Update or create changelog with new entry\n */\n update(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): string {\n const existing = this.read();\n\n if (!existing) {\n // Create new changelog\n const newEntry = this.formatEntry(generated, version, metadata);\n return KEEPACHANGELOG_HEADER + newEntry + '\\n';\n }\n\n // Find where to insert new entry (after header, before first version)\n const lines = existing.split('\\n');\n let insertIndex = -1;\n\n // Look for ## [Unreleased] or first ## [ section\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith('## [Unreleased]')) {\n // Merge with existing unreleased section\n const endIndex = this.findSectionEnd(lines, i + 1);\n const existingSectionLines = lines.slice(i, endIndex);\n const mergedSection = this.mergeUnreleasedSection(existingSectionLines, generated, metadata);\n const before = lines.slice(0, i).join('\\n');\n const after = lines.slice(endIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + mergedSection + '\\n' + after;\n }\n if (line.startsWith('## [') && insertIndex === -1) {\n insertIndex = i;\n break;\n }\n }\n\n const newEntry = this.formatEntry(generated, version, metadata);\n\n if (insertIndex === -1) {\n // No version sections found, append after header\n return existing.trimEnd() + '\\n\\n' + newEntry + '\\n';\n }\n\n // Insert before first version\n const before = lines.slice(0, insertIndex).join('\\n');\n const after = lines.slice(insertIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newEntry + '\\n\\n' + after;\n }\n\n /**\n * Merge new entries into existing Unreleased section\n */\n private mergeUnreleasedSection(\n existingLines: string[],\n generated: GeneratedChangelog,\n metadata?: ChangelogMetadata\n ): string {\n // Parse existing sections\n const existingSections: Map<string, string[]> = new Map();\n let currentSection: string | null = null;\n\n for (const line of existingLines) {\n if (line.startsWith('### ')) {\n currentSection = line.slice(4).trim();\n if (!existingSections.has(currentSection)) {\n existingSections.set(currentSection, []);\n }\n } else if (currentSection && line.startsWith('- ')) {\n existingSections.get(currentSection)!.push(line.slice(2));\n }\n }\n\n // Merge new sections\n for (const section of generated.sections) {\n const existing = existingSections.get(section.type) ?? [];\n // Add new items that don't already exist\n for (const item of section.items) {\n if (!existing.includes(item)) {\n existing.push(item);\n }\n }\n existingSections.set(section.type, existing);\n }\n\n // Build merged entry\n const versionStr = 'Unreleased';\n const headerParts: string[] = [`## [${versionStr}]`];\n\n if (this.config.includeDate) {\n const now = metadata?.timestamp ?? new Date();\n let dateStr = now.toISOString().split('T')[0];\n if (this.config.includeTime) {\n const timeStr = now.toTimeString().split(' ')[0].slice(0, 5);\n dateStr += ` ${timeStr}`;\n }\n headerParts.push(`- ${dateStr}`);\n }\n\n if (this.config.includeAuthor && metadata?.author) {\n headerParts.push(`by ${metadata.author}`);\n }\n\n if (this.config.includeCommitLink && metadata?.commitHash) {\n const shortHash = metadata.commitHash.slice(0, 7);\n if (this.config.repoUrl) {\n const commitUrl = `${this.config.repoUrl.replace(/\\/$/, '')}/commit/${metadata.commitHash}`;\n headerParts.push(`([${shortHash}](${commitUrl}))`);\n } else {\n headerParts.push(`(${shortHash})`);\n }\n }\n\n const headerLine = headerParts.join(' ');\n\n // Sort and format sections\n const sortedSections: ChangelogSection[] = [];\n for (const type of SECTION_ORDER) {\n const items = existingSections.get(type);\n if (items && items.length > 0) {\n sortedSections.push({ type, items });\n }\n }\n\n const sectionLines = sortedSections\n .map((section) => this.formatSection(section))\n .join('\\n\\n');\n\n return `${headerLine}\\n\\n${sectionLines}`;\n }\n\n private findSectionEnd(lines: string[], startIndex: number): number {\n for (let i = startIndex; i < lines.length; i++) {\n if (lines[i].startsWith('## [')) {\n return i;\n }\n }\n return lines.length;\n }\n\n /**\n * Write changelog to file\n */\n write(content: string): void {\n writeFileSync(this.filePath, content, 'utf-8');\n }\n\n /**\n * Get the file path\n */\n getFilePath(): string {\n return this.filePath;\n }\n\n /**\n * Get JSON file path if configured\n */\n getJsonFilePath(): string | null {\n if (!this.config.jsonFile) return null;\n return resolve(process.cwd(), this.config.jsonFile);\n }\n\n /**\n * Read existing JSON changelog\n */\n readJson(): ChangelogJson | null {\n const jsonPath = this.getJsonFilePath();\n if (!jsonPath || !existsSync(jsonPath)) {\n return null;\n }\n try {\n const content = readFileSync(jsonPath, 'utf-8');\n return JSON.parse(content) as ChangelogJson;\n } catch {\n return null;\n }\n }\n\n /**\n * Create a JSON release entry from generated changelog\n */\n createJsonRelease(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): ChangelogJsonRelease {\n const now = metadata?.timestamp ?? new Date();\n const sections: Record<string, string[]> = {};\n\n for (const section of generated.sections) {\n sections[section.type] = section.items;\n }\n\n const release: ChangelogJsonRelease = {\n version: version ?? 'Unreleased',\n date: now.toISOString().split('T')[0],\n sections,\n };\n\n if (this.config.includeTime) {\n release.time = now.toTimeString().split(' ')[0].slice(0, 5);\n }\n\n if (this.config.includeAuthor && metadata?.author) {\n release.author = metadata.author;\n }\n\n if (this.config.includeCommitLink && metadata?.commitHash) {\n release.commitHash = metadata.commitHash;\n }\n\n return release;\n }\n\n /**\n * Update JSON changelog with new release\n */\n updateJson(generated: GeneratedChangelog, version?: string, metadata?: ChangelogMetadata): ChangelogJson {\n const newRelease = this.createJsonRelease(generated, version, metadata);\n const existing = this.readJson();\n\n if (!existing) {\n return { releases: [newRelease] };\n }\n\n // Find and merge or prepend\n const unreleasedIndex = existing.releases.findIndex(r => r.version === 'Unreleased');\n\n if (unreleasedIndex >= 0 && newRelease.version === 'Unreleased') {\n // Merge with existing unreleased\n const existingRelease = existing.releases[unreleasedIndex];\n for (const [type, items] of Object.entries(newRelease.sections)) {\n const existingItems = existingRelease.sections[type] ?? [];\n for (const item of items) {\n if (!existingItems.includes(item)) {\n existingItems.push(item);\n }\n }\n existingRelease.sections[type] = existingItems;\n }\n // Update metadata to latest\n existingRelease.date = newRelease.date;\n if (newRelease.time) existingRelease.time = newRelease.time;\n if (newRelease.author) existingRelease.author = newRelease.author;\n if (newRelease.commitHash) existingRelease.commitHash = newRelease.commitHash;\n } else {\n // Prepend new release\n existing.releases.unshift(newRelease);\n }\n\n return existing;\n }\n\n /**\n * Write JSON changelog to file\n * Applies Biome formatting: single-element arrays inline, trailing newline\n */\n writeJson(data: ChangelogJson): void {\n const jsonPath = this.getJsonFilePath();\n if (!jsonPath) return;\n const formatted = this.formatJsonForBiome(data);\n writeFileSync(jsonPath, formatted, 'utf-8');\n }\n\n /**\n * Format JSON with Biome-compatible style:\n * - Single-element arrays are inline: [\"item\"] instead of multiline\n * - Trailing newline at end of file\n */\n private formatJsonForBiome(data: ChangelogJson): string {\n let json = JSON.stringify(data, null, 2);\n\n // Convert single-element arrays from multiline to inline\n // Matches: [\\n \"content\"\\n ] and converts to [\"content\"]\n json = json.replace(/\\[\\n\\s+(\"(?:[^\"\\\\]|\\\\.)*\")\\n\\s+\\]/g, '[$1]');\n\n // Add trailing newline\n return json + '\\n';\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","resolve","config","readFileSync","writeFileSync","existsSync","resolve","newEntry","before","after","readFileSync","resolve","existsSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tst-changelog",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI-powered changelog generator using OpenRouter",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",