tst-changelog 0.1.0 → 0.1.1

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
@@ -53,6 +53,10 @@ interface CLIOptions {
53
53
  * Load configuration from yaml file
54
54
  */
55
55
  declare function loadConfig(configPath?: string): Config;
56
+ /**
57
+ * Initialize a new config file with defaults
58
+ */
59
+ declare function initConfig(fileName?: string): string;
56
60
 
57
61
  declare class GitService {
58
62
  private git;
@@ -133,4 +137,4 @@ declare class ChangelogService {
133
137
  getFilePath(): string;
134
138
  }
135
139
 
136
- export { type AIConfig, AIService, type CLIOptions, type ChangeType, type ChangelogConfig, type ChangelogEntry, type ChangelogSection, ChangelogService, type CommitInfo, type Config, type GeneratedChangelog, type GitConfig, GitService, type StagedChanges, loadConfig };
140
+ export { type AIConfig, AIService, type CLIOptions, type ChangeType, type ChangelogConfig, type ChangelogEntry, type ChangelogSection, ChangelogService, type CommitInfo, type Config, type GeneratedChangelog, type GitConfig, GitService, type StagedChanges, initConfig, loadConfig };
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/config.ts
7
- import { readFileSync, existsSync } from "fs";
7
+ import { readFileSync, existsSync, writeFileSync } from "fs";
8
8
  import { resolve } from "path";
9
- import { parse } from "yaml";
9
+ import { parse, stringify } from "yaml";
10
10
  var DEFAULT_CONFIG = {
11
11
  ai: {
12
12
  provider: "openrouter",
@@ -82,6 +82,32 @@ function loadConfig(configPath) {
82
82
  const merged = deepMerge(DEFAULT_CONFIG, parsed);
83
83
  return resolveConfigEnvVars(merged);
84
84
  }
85
+ function initConfig(fileName = "tst-changelog.yaml") {
86
+ const filePath = resolve(process.cwd(), fileName);
87
+ if (existsSync(filePath)) {
88
+ throw new Error(`Config file already exists: ${filePath}`);
89
+ }
90
+ const configTemplate = {
91
+ ai: {
92
+ provider: "openrouter",
93
+ model: "anthropic/claude-3-haiku",
94
+ token: "${OPENROUTER_API_KEY}"
95
+ },
96
+ changelog: {
97
+ file: "CHANGELOG.md",
98
+ format: "keepachangelog",
99
+ includeDate: true,
100
+ groupBy: "type"
101
+ },
102
+ git: {
103
+ baseBranch: "main",
104
+ analyzeDepth: 50
105
+ }
106
+ };
107
+ const content = stringify(configTemplate, { lineWidth: 0 });
108
+ writeFileSync(filePath, content, "utf-8");
109
+ return filePath;
110
+ }
85
111
 
86
112
  // src/git.ts
87
113
  import simpleGit from "simple-git";
@@ -320,7 +346,7 @@ var AIService = class {
320
346
  };
321
347
 
322
348
  // src/changelog.ts
323
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
349
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
324
350
  import { resolve as resolve2 } from "path";
325
351
  var KEEPACHANGELOG_HEADER = `# Changelog
326
352
 
@@ -416,7 +442,7 @@ ${items}`;
416
442
  * Write changelog to file
417
443
  */
418
444
  write(content) {
419
- writeFileSync(this.filePath, content, "utf-8");
445
+ writeFileSync2(this.filePath, content, "utf-8");
420
446
  }
421
447
  /**
422
448
  * Get the file path
@@ -428,7 +454,21 @@ ${items}`;
428
454
 
429
455
  // src/index.ts
430
456
  var program = new Command();
431
- program.name("tst-changelog").description("AI-powered changelog generator using OpenRouter").version("0.1.0").option("-c, --config <path>", "Path to config file").option("-d, --dry-run", "Preview without modifying files").option("-v, --verbose", "Enable verbose output").action(run);
457
+ program.name("tst-changelog").description("AI-powered changelog generator using OpenRouter").version("0.1.0");
458
+ program.command("init").description("Create a default configuration file").option("-f, --file <name>", "Config file name", "tst-changelog.yaml").action((options) => {
459
+ try {
460
+ const filePath = initConfig(options.file);
461
+ console.log(`Created config file: ${filePath}`);
462
+ console.log("\nNext steps:");
463
+ console.log("1. Set the OPENROUTER_API_KEY environment variable");
464
+ console.log("2. Adjust settings in the config file as needed");
465
+ console.log("3. Run: npx tst-changelog generate");
466
+ } catch (error) {
467
+ console.error("Error:", error instanceof Error ? error.message : error);
468
+ process.exit(1);
469
+ }
470
+ });
471
+ program.command("generate", { isDefault: true }).description("Generate changelog from staged changes").option("-c, --config <path>", "Path to config file").option("-d, --dry-run", "Preview without modifying files").option("-v, --verbose", "Enable verbose output").action(run);
432
472
  async function run(options) {
433
473
  const verbose = options.verbose ?? false;
434
474
  try {
@@ -498,6 +538,7 @@ export {
498
538
  AIService,
499
539
  ChangelogService,
500
540
  GitService,
541
+ initConfig,
501
542
  loadConfig
502
543
  };
503
544
  //# sourceMappingURL=index.js.map
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 { Command } from 'commander';\nimport { loadConfig } from './config.js';\nimport { GitService } from './git.js';\nimport { AIService } from './ai.js';\nimport { ChangelogService } from './changelog.js';\nimport type { CLIOptions } from './types.js';\n\nconst program = new Command();\n\nprogram\n .name('tst-changelog')\n .description('AI-powered changelog generator using OpenRouter')\n .version('0.1.0')\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 .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 // Get staged changes\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 // Update changelog\n const newContent = changelog.update(generated);\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n console.log('\\n--- New entry ---');\n console.log(changelog.formatEntry(generated));\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Write and stage\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n await git.stageFile(config.changelog.file);\n console.log('Staged changelog file');\n\n console.log('Done!');\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 } 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 } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse } from 'yaml';\nimport type { Config } from './types.js';\n\nconst DEFAULT_CONFIG: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-3-haiku',\n token: '',\n },\n changelog: {\n file: 'CHANGELOG.md',\n format: 'keepachangelog',\n includeDate: true,\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 console.warn('No config file found, using defaults');\n return resolveConfigEnvVars(DEFAULT_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 return resolveConfigEnvVars(merged);\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","import type { AIConfig, CommitInfo, StagedChanges, GeneratedChangelog, ChangelogSection, ChangeType } from './types.js';\n\nconst OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';\n\nconst SYSTEM_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 1\", \"description 2\"]\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- 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\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.slice(0, 20)) {\n parts.push(`- ${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: SYSTEM_PROMPT },\n { role: 'user', content: prompt },\n ],\n temperature: 0.3,\n max_tokens: 1000,\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 } 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): string {\n const date = this.config.includeDate\n ? new Date().toISOString().split('T')[0]\n : '';\n\n const versionStr = version ?? 'Unreleased';\n const headerLine = date ? `## [${versionStr}] - ${date}` : `## [${versionStr}]`;\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 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) => `- ${item}`).join('\\n');\n return `### ${section.type}\\n\\n${items}`;\n }\n\n /**\n * Update or create changelog with new entry\n */\n update(generated: GeneratedChangelog, version?: string): string {\n const newEntry = this.formatEntry(generated, version);\n const existing = this.read();\n\n if (!existing) {\n // Create new changelog\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 // Replace unreleased section\n const endIndex = this.findSectionEnd(lines, i + 1);\n const before = lines.slice(0, i).join('\\n');\n const after = lines.slice(endIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newEntry + '\\n\\n' + after;\n }\n if (line.startsWith('## [') && insertIndex === -1) {\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' + 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 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"],"mappings":"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","names":["readFileSync","existsSync","resolve","before","after"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/git.ts","../src/ai.ts","../src/changelog.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { loadConfig, initConfig } from './config.js';\nimport { GitService } from './git.js';\nimport { AIService } from './ai.js';\nimport { ChangelogService } from './changelog.js';\nimport type { CLIOptions } from './types.js';\n\nconst program = new Command();\n\nprogram\n .name('tst-changelog')\n .description('AI-powered changelog generator using OpenRouter')\n .version('0.1.0');\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 filePath = initConfig(options.file);\n console.log(`Created config file: ${filePath}`);\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 console.log('3. Run: npx tst-changelog generate');\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')\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 .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 // Get staged changes\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 // Update changelog\n const newContent = changelog.update(generated);\n\n if (options.dryRun) {\n console.log('\\n--- DRY RUN ---');\n console.log('Would update changelog at:', changelog.getFilePath());\n console.log('\\n--- New entry ---');\n console.log(changelog.formatEntry(generated));\n console.log('--- End ---\\n');\n process.exit(0);\n }\n\n // Write and stage\n changelog.write(newContent);\n console.log(`Updated: ${changelog.getFilePath()}`);\n\n await git.stageFile(config.changelog.file);\n console.log('Staged changelog file');\n\n console.log('Done!');\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 } 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 } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse, stringify } from 'yaml';\nimport type { Config } from './types.js';\n\nconst DEFAULT_CONFIG: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-3-haiku',\n token: '',\n },\n changelog: {\n file: 'CHANGELOG.md',\n format: 'keepachangelog',\n includeDate: true,\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 console.warn('No config file found, using defaults');\n return resolveConfigEnvVars(DEFAULT_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 return resolveConfigEnvVars(merged);\n}\n\n/**\n * Initialize a new config file with defaults\n */\nexport function initConfig(fileName = 'tst-changelog.yaml'): string {\n const filePath = resolve(process.cwd(), fileName);\n\n if (existsSync(filePath)) {\n throw new Error(`Config file already exists: ${filePath}`);\n }\n\n const configTemplate: Config = {\n ai: {\n provider: 'openrouter',\n model: 'anthropic/claude-3-haiku',\n token: '${OPENROUTER_API_KEY}',\n },\n changelog: {\n file: 'CHANGELOG.md',\n format: 'keepachangelog',\n includeDate: true,\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 return filePath;\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","import type { AIConfig, CommitInfo, StagedChanges, GeneratedChangelog, ChangelogSection, ChangeType } from './types.js';\n\nconst OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';\n\nconst SYSTEM_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 1\", \"description 2\"]\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- 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\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.slice(0, 20)) {\n parts.push(`- ${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: SYSTEM_PROMPT },\n { role: 'user', content: prompt },\n ],\n temperature: 0.3,\n max_tokens: 1000,\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 } 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): string {\n const date = this.config.includeDate\n ? new Date().toISOString().split('T')[0]\n : '';\n\n const versionStr = version ?? 'Unreleased';\n const headerLine = date ? `## [${versionStr}] - ${date}` : `## [${versionStr}]`;\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 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) => `- ${item}`).join('\\n');\n return `### ${section.type}\\n\\n${items}`;\n }\n\n /**\n * Update or create changelog with new entry\n */\n update(generated: GeneratedChangelog, version?: string): string {\n const newEntry = this.formatEntry(generated, version);\n const existing = this.read();\n\n if (!existing) {\n // Create new changelog\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 // Replace unreleased section\n const endIndex = this.findSectionEnd(lines, i + 1);\n const before = lines.slice(0, i).join('\\n');\n const after = lines.slice(endIndex).join('\\n');\n return before + (before.endsWith('\\n') ? '' : '\\n') + newEntry + '\\n\\n' + after;\n }\n if (line.startsWith('## [') && insertIndex === -1) {\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' + 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 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"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","resolve","before","after"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tst-changelog",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AI-powered changelog generator using OpenRouter",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",