@releasehub/cli 1.0.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.
Files changed (41) hide show
  1. package/dist/commands/ai.d.ts +3 -0
  2. package/dist/commands/ai.d.ts.map +1 -0
  3. package/dist/commands/ai.js +215 -0
  4. package/dist/commands/ai.js.map +1 -0
  5. package/dist/commands/auth.d.ts +3 -0
  6. package/dist/commands/auth.d.ts.map +1 -0
  7. package/dist/commands/auth.js +130 -0
  8. package/dist/commands/auth.js.map +1 -0
  9. package/dist/commands/generate.d.ts +12 -0
  10. package/dist/commands/generate.d.ts.map +1 -0
  11. package/dist/commands/generate.js +105 -0
  12. package/dist/commands/generate.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +33 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lib/ai.d.ts +15 -0
  18. package/dist/lib/ai.d.ts.map +1 -0
  19. package/dist/lib/ai.js +128 -0
  20. package/dist/lib/ai.js.map +1 -0
  21. package/dist/lib/config.d.ts +21 -0
  22. package/dist/lib/config.d.ts.map +1 -0
  23. package/dist/lib/config.js +69 -0
  24. package/dist/lib/config.js.map +1 -0
  25. package/dist/lib/errors.d.ts +15 -0
  26. package/dist/lib/errors.d.ts.map +1 -0
  27. package/dist/lib/errors.js +49 -0
  28. package/dist/lib/errors.js.map +1 -0
  29. package/dist/lib/formatters.d.ts +12 -0
  30. package/dist/lib/formatters.d.ts.map +1 -0
  31. package/dist/lib/formatters.js +121 -0
  32. package/dist/lib/formatters.js.map +1 -0
  33. package/dist/lib/git.d.ts +13 -0
  34. package/dist/lib/git.d.ts.map +1 -0
  35. package/dist/lib/git.js +52 -0
  36. package/dist/lib/git.js.map +1 -0
  37. package/dist/lib/github.d.ts +34 -0
  38. package/dist/lib/github.d.ts.map +1 -0
  39. package/dist/lib/github.js +166 -0
  40. package/dist/lib/github.js.map +1 -0
  41. package/package.json +44 -0
package/dist/lib/ai.js ADDED
@@ -0,0 +1,128 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ import OpenAI from 'openai';
3
+ import { getActiveProvider, getActiveAIKey } from './config.js';
4
+ import { AuthError, ApiError } from './errors.js';
5
+ // ─── Prompt ───────────────────────────────────────────────────────────────────
6
+ const SYSTEM_PROMPT = `You are a release communication assistant for software teams.
7
+
8
+ Your job is to analyze a list of merged pull requests and:
9
+ 1. Classify each PR into a category
10
+ 2. Decide if it should be visible to end users
11
+ 3. Rewrite the title in clear, non-technical language for users
12
+
13
+ ## Categories
14
+ - feature: New capability that users can now use
15
+ - improvement: An existing feature is faster, easier, or more reliable
16
+ - bugfix: A problem that users experienced has been fixed
17
+ - breaking: A change that requires user action or breaks existing behavior
18
+ - internal: Technical change with no user-facing impact (hide from users)
19
+
20
+ ## Rules
21
+ - Refactors → internal (always)
22
+ - Dependency updates → internal (always)
23
+ - CI/CD changes → internal (always)
24
+ - Test additions → internal (unless the PR title describes a new feature)
25
+ - Breaking changes → always visible, never hide them
26
+ - When unsure: lean toward showing rather than hiding
27
+
28
+ ## Rewriting rules
29
+ - Remove all technical jargon
30
+ - Write for a non-technical end user
31
+ - Present tense, action verbs ("You can now...", "Fixed an issue where...")
32
+ - Max 80 characters per rewritten title
33
+
34
+ ## Output format
35
+ Return a JSON array. One object per PR. No prose, no markdown, just raw JSON.
36
+ [
37
+ {
38
+ "original_title": "...",
39
+ "rewritten_title": "...",
40
+ "category": "feature|improvement|bugfix|breaking|internal",
41
+ "visible": true,
42
+ "confidence": 0.95,
43
+ "reasoning": "one sentence"
44
+ }
45
+ ]`;
46
+ function buildUserPrompt(prs) {
47
+ const list = prs.map(pr => {
48
+ const labels = pr.labels.length ? `\nLabels: ${pr.labels.join(', ')}` : '';
49
+ const issues = pr.linked_issues.length ? `\nLinked issues: ${pr.linked_issues.join(', ')}` : '';
50
+ const body = pr.body ? `\nBody: ${pr.body.slice(0, 300)}` : '';
51
+ return `#${pr.number}: ${pr.title}${labels}${issues}${body}`;
52
+ }).join('\n\n');
53
+ return `Analyze these ${prs.length} pull requests:\n\n${list}`;
54
+ }
55
+ function parseResponse(raw) {
56
+ const cleaned = raw
57
+ .replace(/```(?:json)?\n?/g, '')
58
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
59
+ .trim();
60
+ return JSON.parse(cleaned);
61
+ }
62
+ // ─── Providers ────────────────────────────────────────────────────────────────
63
+ const ANTHROPIC_MODEL = 'claude-sonnet-4-5';
64
+ const OPENAI_MODEL = 'gpt-4o';
65
+ const BATCH_SIZE = 20;
66
+ async function analyzeWithAnthropic(prs) {
67
+ const key = getActiveAIKey();
68
+ if (!key)
69
+ throw new AuthError('No Anthropic key found. Run: releasehub ai add-key');
70
+ const client = new Anthropic({ apiKey: key });
71
+ const results = [];
72
+ for (let i = 0; i < prs.length; i += BATCH_SIZE) {
73
+ const batch = prs.slice(i, i + BATCH_SIZE);
74
+ const message = await client.messages.create({
75
+ model: ANTHROPIC_MODEL,
76
+ max_tokens: 4096,
77
+ system: SYSTEM_PROMPT,
78
+ messages: [{ role: 'user', content: buildUserPrompt(batch) }],
79
+ });
80
+ const content = message.content[0];
81
+ if (!content || content.type !== 'text')
82
+ throw new ApiError('Unexpected response from Anthropic API');
83
+ results.push(...parseResponse(content.text));
84
+ }
85
+ return results;
86
+ }
87
+ async function analyzeWithOpenAI(prs) {
88
+ const key = getActiveAIKey();
89
+ if (!key)
90
+ throw new AuthError('No OpenAI key found. Run: releasehub ai add-key');
91
+ const client = new OpenAI({ apiKey: key });
92
+ const results = [];
93
+ for (let i = 0; i < prs.length; i += BATCH_SIZE) {
94
+ const batch = prs.slice(i, i + BATCH_SIZE);
95
+ const completion = await client.chat.completions.create({
96
+ model: OPENAI_MODEL,
97
+ messages: [
98
+ { role: 'system', content: SYSTEM_PROMPT },
99
+ { role: 'user', content: buildUserPrompt(batch) },
100
+ ],
101
+ });
102
+ const content = completion.choices[0]?.message?.content;
103
+ if (!content)
104
+ throw new ApiError('Unexpected response from OpenAI API');
105
+ results.push(...parseResponse(content));
106
+ }
107
+ return results;
108
+ }
109
+ // ─── Public API ───────────────────────────────────────────────────────────────
110
+ export async function analyzePullRequests(prs) {
111
+ const provider = getActiveProvider();
112
+ let changes;
113
+ switch (provider) {
114
+ case 'anthropic':
115
+ changes = await analyzeWithAnthropic(prs);
116
+ break;
117
+ case 'openai':
118
+ changes = await analyzeWithOpenAI(prs);
119
+ break;
120
+ default: throw new ApiError(`Unsupported AI provider: ${provider}`);
121
+ }
122
+ const order = {
123
+ breaking: 0, feature: 1, improvement: 2, bugfix: 3, internal: 4,
124
+ };
125
+ changes.sort((a, b) => (order[a.category] ?? 5) - (order[b.category] ?? 5));
126
+ return { changes };
127
+ }
128
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/lib/ai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type AIProvider = 'anthropic' | 'openai';
2
+ export declare const AI_PROVIDERS: AIProvider[];
3
+ export declare const AI_PROVIDER_LABELS: Record<AIProvider, string>;
4
+ export declare const AI_PROVIDER_KEY_URLS: Record<AIProvider, string>;
5
+ export interface Config {
6
+ github_token?: string;
7
+ ai_provider?: AIProvider;
8
+ anthropic_key?: string;
9
+ openai_key?: string;
10
+ default_format?: 'github-release' | 'changelog' | 'slack';
11
+ }
12
+ export declare function readConfig(): Config;
13
+ export declare function writeConfig(config: Config): void;
14
+ export declare function updateConfig(partial: Partial<Config>): void;
15
+ export declare function getGitHubToken(): string | undefined;
16
+ export declare function getAnthropicKey(): string | undefined;
17
+ export declare function getOpenAIKey(): string | undefined;
18
+ export declare function getActiveProvider(): AIProvider;
19
+ export declare function getActiveAIKey(): string | undefined;
20
+ export declare function getKeyForProvider(provider: AIProvider): string | undefined;
21
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE/C,eAAO,MAAM,YAAY,EAAE,UAAU,EAA4B,CAAA;AAEjE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAGzD,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAG3D,CAAA;AAED,MAAM,WAAW,MAAM;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,UAAU,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,gBAAgB,GAAG,WAAW,GAAG,OAAO,CAAA;CAC1D;AAMD,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAQhD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAE3D;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAEnD;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpD;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjD;AAED,wBAAgB,iBAAiB,IAAI,UAAU,CAE9C;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAMnD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAK1E"}
@@ -0,0 +1,69 @@
1
+ import { homedir } from 'os';
2
+ import { join } from 'path';
3
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from 'fs';
4
+ import { ConfigError } from './errors.js';
5
+ const CONFIG_DIR = join(homedir(), '.releasehub');
6
+ const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
7
+ export const AI_PROVIDERS = ['anthropic', 'openai'];
8
+ export const AI_PROVIDER_LABELS = {
9
+ anthropic: 'Anthropic (Claude)',
10
+ openai: 'OpenAI (GPT-4o)',
11
+ };
12
+ export const AI_PROVIDER_KEY_URLS = {
13
+ anthropic: 'https://console.anthropic.com',
14
+ openai: 'https://platform.openai.com/api-keys',
15
+ };
16
+ function ensureConfigDir() {
17
+ if (!existsSync(CONFIG_DIR))
18
+ mkdirSync(CONFIG_DIR, { recursive: true });
19
+ }
20
+ export function readConfig() {
21
+ ensureConfigDir();
22
+ if (!existsSync(CONFIG_PATH))
23
+ return {};
24
+ try {
25
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
26
+ }
27
+ catch {
28
+ throw new ConfigError(`Failed to read config at ${CONFIG_PATH}`);
29
+ }
30
+ }
31
+ export function writeConfig(config) {
32
+ ensureConfigDir();
33
+ try {
34
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
35
+ chmodSync(CONFIG_PATH, 0o600);
36
+ }
37
+ catch {
38
+ throw new ConfigError(`Failed to write config at ${CONFIG_PATH}`);
39
+ }
40
+ }
41
+ export function updateConfig(partial) {
42
+ writeConfig({ ...readConfig(), ...partial });
43
+ }
44
+ export function getGitHubToken() {
45
+ return process.env['RELEASEHUB_GITHUB_TOKEN'] ?? readConfig().github_token;
46
+ }
47
+ export function getAnthropicKey() {
48
+ return process.env['RELEASEHUB_ANTHROPIC_KEY'] ?? readConfig().anthropic_key;
49
+ }
50
+ export function getOpenAIKey() {
51
+ return process.env['RELEASEHUB_OPENAI_KEY'] ?? readConfig().openai_key;
52
+ }
53
+ export function getActiveProvider() {
54
+ return readConfig().ai_provider ?? 'anthropic';
55
+ }
56
+ export function getActiveAIKey() {
57
+ const provider = getActiveProvider();
58
+ switch (provider) {
59
+ case 'anthropic': return getAnthropicKey();
60
+ case 'openai': return getOpenAIKey();
61
+ }
62
+ }
63
+ export function getKeyForProvider(provider) {
64
+ switch (provider) {
65
+ case 'anthropic': return getAnthropicKey();
66
+ case 'openai': return getOpenAIKey();
67
+ }
68
+ }
69
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export declare class ReleaseHubError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class AuthError extends ReleaseHubError {
5
+ constructor(message?: string);
6
+ }
7
+ export declare class ConfigError extends ReleaseHubError {
8
+ constructor(message: string);
9
+ }
10
+ export declare class ApiError extends ReleaseHubError {
11
+ readonly statusCode?: number | undefined;
12
+ constructor(message: string, statusCode?: number | undefined);
13
+ }
14
+ export declare function handleError(err: unknown): never;
15
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAEA,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,SAAU,SAAQ,eAAe;gBAChC,OAAO,SAAkD;CAItE;AAED,qBAAa,WAAY,SAAQ,eAAe;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,QAAS,SAAQ,eAAe;aAGzB,UAAU,CAAC,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,UAAU,CAAC,EAAE,MAAM,YAAA;CAKtC;AAOD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CAe/C"}
@@ -0,0 +1,49 @@
1
+ import chalk from 'chalk';
2
+ export class ReleaseHubError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'ReleaseHubError';
6
+ }
7
+ }
8
+ export class AuthError extends ReleaseHubError {
9
+ constructor(message = 'Not authenticated. Run: releasehub auth login') {
10
+ super(message);
11
+ this.name = 'AuthError';
12
+ }
13
+ }
14
+ export class ConfigError extends ReleaseHubError {
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = 'ConfigError';
18
+ }
19
+ }
20
+ export class ApiError extends ReleaseHubError {
21
+ statusCode;
22
+ constructor(message, statusCode) {
23
+ super(message);
24
+ this.statusCode = statusCode;
25
+ this.name = 'ApiError';
26
+ }
27
+ }
28
+ const HINTS = {
29
+ AuthError: 'Run: releasehub auth login',
30
+ ConfigError: 'Run: releasehub --help for usage',
31
+ };
32
+ export function handleError(err) {
33
+ console.error('');
34
+ if (err instanceof ReleaseHubError) {
35
+ console.error(` ${chalk.red('✖')} ${err.message}`);
36
+ const hint = HINTS[err.name];
37
+ if (hint)
38
+ console.error(` ${chalk.dim(hint)}`);
39
+ }
40
+ else if (err instanceof Error) {
41
+ console.error(` ${chalk.red('✖')} ${err.message}`);
42
+ }
43
+ else {
44
+ console.error(` ${chalk.red('✖')} An unexpected error occurred.`);
45
+ }
46
+ console.error('');
47
+ process.exit(1);
48
+ }
49
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,SAAU,SAAQ,eAAe;IAC5C,YAAY,OAAO,GAAG,+CAA+C;QACnE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,eAAe;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,eAAe;IAGzB;IAFlB,YACE,OAAe,EACC,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAA;QAFE,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;IACxB,CAAC;CACF;AAED,MAAM,KAAK,GAA2B;IACpC,SAAS,EAAI,4BAA4B;IACzC,WAAW,EAAE,kCAAkC;CAChD,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAEjB,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,IAAI;YAAE,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACjD,CAAC;SAAM,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACrD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;IACpE,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AnalyzedChange } from './ai.js';
2
+ export type OutputFormat = 'github-release' | 'changelog' | 'slack';
3
+ interface FormatContext {
4
+ version: string;
5
+ changes: AnalyzedChange[];
6
+ }
7
+ export declare function formatGitHubRelease({ version, changes }: FormatContext): string;
8
+ export declare function formatChangelog({ version, changes }: FormatContext): string;
9
+ export declare function formatSlack({ version, changes }: FormatContext): string;
10
+ export declare function formatOutput(format: string, ctx: FormatContext): string;
11
+ export {};
12
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../src/lib/formatters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,WAAW,GAAG,OAAO,CAAA;AAEnE,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,cAAc,EAAE,CAAA;CAC1B;AAoDD,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,aAAa,GAAG,MAAM,CAmB/E;AAED,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,aAAa,GAAG,MAAM,CAqB3E;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,aAAa,GAAG,MAAM,CAoCvE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAOvE"}
@@ -0,0 +1,121 @@
1
+ const CATEGORY_HEADERS = {
2
+ breaking: '⚠️ Breaking Changes',
3
+ feature: '✨ New Features',
4
+ improvement: '🔧 Improvements',
5
+ bugfix: '🐛 Bug Fixes',
6
+ };
7
+ const CATEGORY_EMOJI = {
8
+ breaking: '⚠️',
9
+ feature: '✨',
10
+ improvement: '🔧',
11
+ bugfix: '🐛',
12
+ };
13
+ const SLACK_MAX_ITEMS = 6;
14
+ function groupByCategory(changes) {
15
+ const groups = new Map();
16
+ const order = ['breaking', 'feature', 'improvement', 'bugfix'];
17
+ for (const cat of order) {
18
+ const items = changes.filter(c => c.category === cat);
19
+ if (items.length > 0)
20
+ groups.set(cat, items);
21
+ }
22
+ return groups;
23
+ }
24
+ function buildSummary(groups) {
25
+ const parts = [];
26
+ const features = groups.get('feature');
27
+ const improvements = groups.get('improvement');
28
+ const bugfixes = groups.get('bugfix');
29
+ const breaking = groups.get('breaking');
30
+ if (breaking?.length)
31
+ parts.push(`${breaking.length} breaking change${breaking.length > 1 ? 's' : ''}`);
32
+ if (features?.length)
33
+ parts.push(`${features.length} new feature${features.length > 1 ? 's' : ''}`);
34
+ if (improvements?.length)
35
+ parts.push(`${improvements.length} improvement${improvements.length > 1 ? 's' : ''}`);
36
+ if (bugfixes?.length)
37
+ parts.push(`${bugfixes.length} bug fix${bugfixes.length > 1 ? 'es' : ''}`);
38
+ if (parts.length === 0)
39
+ return '';
40
+ if (parts.length === 1)
41
+ return `This release includes ${parts[0]}.`;
42
+ const last = parts.pop();
43
+ return `This release includes ${parts.join(', ')} and ${last}.`;
44
+ }
45
+ function truncate(str, max) {
46
+ return str.length > max ? str.slice(0, max - 1) + '…' : str;
47
+ }
48
+ export function formatGitHubRelease({ version, changes }) {
49
+ const visible = changes.filter(c => c.visible);
50
+ if (visible.length === 0)
51
+ return `## ${version}\n\nNo user-facing changes in this release.\n`;
52
+ const groups = groupByCategory(visible);
53
+ const summary = buildSummary(groups);
54
+ const lines = [`## ${version}`, ''];
55
+ if (summary)
56
+ lines.push(summary, '');
57
+ for (const [cat, items] of groups) {
58
+ lines.push(`### ${CATEGORY_HEADERS[cat]}`, '');
59
+ for (const item of items) {
60
+ lines.push(`- ${item.rewritten_title}`);
61
+ }
62
+ lines.push('');
63
+ }
64
+ return lines.join('\n').trimEnd() + '\n';
65
+ }
66
+ export function formatChangelog({ version, changes }) {
67
+ const visible = changes.filter(c => c.visible);
68
+ const today = new Date().toISOString().split('T')[0];
69
+ const lines = [`## [${version}] — ${today}`, ''];
70
+ if (visible.length === 0) {
71
+ lines.push('No user-facing changes in this release.', '');
72
+ return lines.join('\n');
73
+ }
74
+ const groups = groupByCategory(visible);
75
+ for (const [cat, items] of groups) {
76
+ lines.push(`### ${CATEGORY_HEADERS[cat]}`, '');
77
+ for (const item of items) {
78
+ lines.push(`- ${item.rewritten_title}`);
79
+ }
80
+ lines.push('');
81
+ }
82
+ return lines.join('\n').trimEnd() + '\n';
83
+ }
84
+ export function formatSlack({ version, changes }) {
85
+ const visible = changes.filter(c => c.visible);
86
+ const lines = [`*🚀 ${version}*`];
87
+ if (visible.length === 0) {
88
+ lines.push('No user-facing changes in this release.');
89
+ return lines.join('\n');
90
+ }
91
+ // Breaking changes always shown in full
92
+ const breaking = visible.filter(c => c.category === 'breaking');
93
+ const rest = visible.filter(c => c.category !== 'breaking');
94
+ // Pick top items up to SLACK_MAX_ITEMS (breaking always included)
95
+ const slots = SLACK_MAX_ITEMS - breaking.length;
96
+ const shown = rest.slice(0, Math.max(slots, 0));
97
+ const overflow = rest.length - shown.length;
98
+ lines.push('');
99
+ if (breaking.length > 0) {
100
+ for (const item of breaking) {
101
+ lines.push(`${CATEGORY_EMOJI.breaking} ${truncate(item.rewritten_title, 80)}`);
102
+ }
103
+ }
104
+ for (const item of shown) {
105
+ const emoji = CATEGORY_EMOJI[item.category] ?? '•';
106
+ lines.push(`${emoji} ${truncate(item.rewritten_title, 80)}`);
107
+ }
108
+ if (overflow > 0) {
109
+ lines.push(`_+ ${overflow} more update${overflow > 1 ? 's' : ''}_`);
110
+ }
111
+ return lines.join('\n');
112
+ }
113
+ export function formatOutput(format, ctx) {
114
+ switch (format) {
115
+ case 'github-release': return formatGitHubRelease(ctx);
116
+ case 'changelog': return formatChangelog(ctx);
117
+ case 'slack': return formatSlack(ctx);
118
+ default: throw new Error(`Unknown format: ${format}. Use: github-release | changelog | slack`);
119
+ }
120
+ }
121
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/lib/formatters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface RepoInfo {
2
+ owner: string;
3
+ name: string;
4
+ }
5
+ /**
6
+ * Detect repo from the current directory's git remote.
7
+ */
8
+ export declare function detectRepo(): RepoInfo;
9
+ /**
10
+ * Parse "owner/name" string into RepoInfo.
11
+ */
12
+ export declare function parseRepo(repo: string): RepoInfo;
13
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAsBD;;GAEG;AACH,wBAAgB,UAAU,IAAI,QAAQ,CAqBrC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAMhD"}
@@ -0,0 +1,52 @@
1
+ import { execSync } from 'child_process';
2
+ import { ConfigError } from './errors.js';
3
+ /**
4
+ * Parse owner/name from a GitHub remote URL.
5
+ * Supports both SSH (git@github.com:owner/repo.git) and HTTPS (https://github.com/owner/repo.git)
6
+ */
7
+ function parseGitHubRemote(url) {
8
+ // SSH: git@github.com:owner/repo.git or git@p-github.com:owner/repo.git
9
+ const sshMatch = url.match(/github\.com[:/]([^/]+)\/([^/\s.]+?)(?:\.git)?$/);
10
+ if (sshMatch) {
11
+ return { owner: sshMatch[1], name: sshMatch[2] };
12
+ }
13
+ // HTTPS: https://github.com/owner/repo.git
14
+ const httpsMatch = url.match(/github\.com\/([^/]+)\/([^/\s.]+?)(?:\.git)?$/);
15
+ if (httpsMatch) {
16
+ return { owner: httpsMatch[1], name: httpsMatch[2] };
17
+ }
18
+ return null;
19
+ }
20
+ /**
21
+ * Detect repo from the current directory's git remote.
22
+ */
23
+ export function detectRepo() {
24
+ try {
25
+ const remoteUrl = execSync('git remote get-url origin', {
26
+ stdio: ['pipe', 'pipe', 'pipe'],
27
+ })
28
+ .toString()
29
+ .trim();
30
+ const repo = parseGitHubRemote(remoteUrl);
31
+ if (!repo) {
32
+ throw new ConfigError(`Remote origin doesn't look like a GitHub repo.\nPass --repo owner/name explicitly.`);
33
+ }
34
+ return repo;
35
+ }
36
+ catch (err) {
37
+ if (err instanceof ConfigError)
38
+ throw err;
39
+ throw new ConfigError(`Not inside a git repository or no remote set.\nPass --repo owner/name explicitly.`);
40
+ }
41
+ }
42
+ /**
43
+ * Parse "owner/name" string into RepoInfo.
44
+ */
45
+ export function parseRepo(repo) {
46
+ const parts = repo.split('/');
47
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
48
+ throw new ConfigError(`Invalid repo format: "${repo}". Expected: owner/name`);
49
+ }
50
+ return { owner: parts[0], name: parts[1] };
51
+ }
52
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAOzC;;;GAGG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,wEAAwE;IACxE,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAA;IAC5E,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,CAAA;IACpD,CAAC;IAED,2CAA2C;IAC3C,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAA;IAC5E,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAE,EAAE,CAAA;IACxD,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YACtD,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC;aACC,QAAQ,EAAE;aACV,IAAI,EAAE,CAAA;QAET,MAAM,IAAI,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,WAAW,CACnB,oFAAoF,CACrF,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW;YAAE,MAAM,GAAG,CAAA;QACzC,MAAM,IAAI,WAAW,CACnB,mFAAmF,CACpF,CAAA;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,WAAW,CAAC,yBAAyB,IAAI,yBAAyB,CAAC,CAAA;IAC/E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { RepoInfo } from './git.js';
2
+ export interface PullRequest {
3
+ number: number;
4
+ title: string;
5
+ body: string | null;
6
+ labels: string[];
7
+ author: string;
8
+ merged_at: string;
9
+ url: string;
10
+ linked_issues: string[];
11
+ }
12
+ export interface Tag {
13
+ name: string;
14
+ sha: string;
15
+ date: string | null;
16
+ }
17
+ /**
18
+ * Fetch all tags for a repo, sorted by date descending.
19
+ */
20
+ export declare function fetchTags(repo: RepoInfo): Promise<Tag[]>;
21
+ /**
22
+ * Fetch merged PRs between two tags.
23
+ */
24
+ export declare function fetchPullRequests(repo: RepoInfo, fromTag: string, toTag: string): Promise<PullRequest[]>;
25
+ export interface GitHubRelease {
26
+ id: number;
27
+ html_url: string;
28
+ name: string;
29
+ }
30
+ /**
31
+ * Create a GitHub Release for the given tag with the provided body.
32
+ */
33
+ export declare function publishGitHubRelease(repo: RepoInfo, tag: string, body: string): Promise<GitHubRelease>;
34
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/lib/github.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAkBD;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAuC9D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,CAAC,CAoExB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CAwBxB"}