@litebox-packages/release-notes-bot 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/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Release Notes Bot
2
+
3
+ Automated release notes generator using GitLab API.
4
+
5
+ ## Setup
6
+
7
+ 1. Install dependencies:
8
+ ```bash
9
+ pnpm install
10
+ ```
11
+
12
+ 2. Build the project:
13
+ ```bash
14
+ pnpm build
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Using npx (Recommended - No installation needed)
20
+
21
+ **Option 1: Using -p flag (most reliable)**
22
+ ```bash
23
+ npx -p @litebox-packages/release-notes-bot release-notes-bot --before <commit-hash-1> --after <commit-hash-2> --projectId <gitlab-project-id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]
24
+ ```
25
+
26
+ **Option 2: Direct npx (may require clearing cache)**
27
+ ```bash
28
+ npx @litebox-packages/release-notes-bot --before <commit-hash-1> --after <commit-hash-2> --projectId <gitlab-project-id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]
29
+ ```
30
+
31
+ If Option 2 doesn't work, try clearing npx cache:
32
+ ```bash
33
+ rm -rf ~/.npm/_npx
34
+ ```
35
+
36
+ ### Development Mode (using ts-node)
37
+
38
+ ```bash
39
+ pnpm dev --before <commit-hash-1> --after <commit-hash-2> --projectId <gitlab-project-id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]
40
+ ```
41
+
42
+ ### Production Mode (after building)
43
+
44
+ ```bash
45
+ pnpm start --before <commit-hash-1> --after <commit-hash-2> --projectId <gitlab-project-id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]
46
+ ```
47
+
48
+ Or directly with node:
49
+
50
+ ```bash
51
+ node dist/cli.js --before <commit-hash-1> --after <commit-hash-2> --projectId <gitlab-project-id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]
52
+ ```
53
+
54
+ ## Arguments
55
+
56
+ - `--before`: The commit hash to compare from (older commit)
57
+ - `--after`: The commit hash to compare to (newer commit)
58
+ - `--projectId`: Your GitLab project ID (can be found in project settings)
59
+ - `--token`: Your GitLab personal access token with `api` scope
60
+ - `--openaiToken`: Your OpenAI API key (starts with `sk-`)
61
+ - `--slackToken`: (Optional) Your Slack bot token (starts with `xoxb-`). If provided, `--slackChannelId` is also required.
62
+ - `--slackChannelId`: (Optional) Slack channel ID or user DM ID where release notes will be sent. Required if `--slackToken` is provided. Slack failures are non-fatal and will only log a warning.
63
+
64
+ ## Example
65
+
66
+ ### Using npx (Recommended)
67
+
68
+ ```bash
69
+ npx -p @litebox-packages/release-notes-bot release-notes-bot --before abc123 --after def456 --projectId 12345 --token glpat-xxxxxxxxxxxxx --openaiToken sk-xxxxxxxxxxxxx --slackToken xoxb-xxxxxxxxxxxxx --slackChannelId C09TVLQ33HN
70
+ ```
71
+
72
+ ### Local Development
73
+
74
+ ```bash
75
+ pnpm dev --before abc123 --after def456 --projectId 12345 --token glpat-xxxxxxxxxxxxx --openaiToken sk-xxxxxxxxxxxxx --slackToken xoxb-xxxxxxxxxxxxx --slackChannelId C09TVLQ33HN
76
+ ```
77
+
78
+ ## GitLab CI Integration
79
+
80
+ In your `.gitlab-ci.yml`, you can use it like this:
81
+
82
+ ```yaml
83
+ generate-release-notes:
84
+ script:
85
+ - npx -p @litebox-packages/release-notes-bot release-notes-bot --before "$CI_COMMIT_BEFORE_SHA" --after "$CI_COMMIT_SHA" --projectId "$CI_PROJECT_ID" --token "$GITLAB_TOKEN" --openaiToken "$OPENAI_TOKEN" --slackToken "$SLACK_TOKEN" --slackChannelId "$SLACK_CHANNEL_ID"
86
+ ```
87
+
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const getDiff_1 = require("./getDiff");
5
+ const tokenEstimator_1 = require("./tokenEstimator");
6
+ const dataSanitizer_1 = require("./dataSanitizer");
7
+ const promptInstructions_1 = require("./promptInstructions");
8
+ const openaiClient_1 = require("./openaiClient");
9
+ const slackClient_1 = require("./slackClient");
10
+ const isAssetFile = (filePath) => {
11
+ const lowerPath = filePath.toLowerCase();
12
+ // Check for asset file extensions
13
+ const assetExtensions = [
14
+ ".svg",
15
+ ".png",
16
+ ".jpg",
17
+ ".jpeg",
18
+ ".gif",
19
+ ".webp",
20
+ ".ico",
21
+ ".bmp",
22
+ ".tiff",
23
+ ".woff",
24
+ ".woff2",
25
+ ".ttf",
26
+ ".eot",
27
+ ".otf",
28
+ ];
29
+ const hasAssetExtension = assetExtensions.some((ext) => lowerPath.endsWith(ext));
30
+ // Check for asset/image directories
31
+ const isInAssetDirectory = lowerPath.includes("/assets/") ||
32
+ lowerPath.includes("/images/") ||
33
+ lowerPath.includes("/public/") ||
34
+ lowerPath.includes("/static/") ||
35
+ lowerPath.startsWith("assets/") ||
36
+ lowerPath.startsWith("images/") ||
37
+ lowerPath.startsWith("public/") ||
38
+ lowerPath.startsWith("static/");
39
+ return hasAssetExtension || isInAssetDirectory;
40
+ };
41
+ const filterAssetDiffs = (diffs) => {
42
+ return diffs.filter((diff) => !isAssetFile(diff.old_path) && !isAssetFile(diff.new_path));
43
+ };
44
+ const parseArgs = () => {
45
+ const args = process.argv.slice(2);
46
+ const parsed = {};
47
+ for (let i = 0; i < args.length; i += 2) {
48
+ const key = args[i]?.replace("--", "");
49
+ const value = args[i + 1];
50
+ if (key && value) {
51
+ parsed[key] = value;
52
+ }
53
+ }
54
+ if (!parsed.before ||
55
+ !parsed.after ||
56
+ !parsed.projectId ||
57
+ !parsed.token ||
58
+ !parsed.openaiToken) {
59
+ console.error("Usage: release-notes-bot --before <hash> --after <hash> --projectId <id> --token <gitlab-token> --openaiToken <openai-token> [--slackToken <slack-token> --slackChannelId <slack-channel-id>]");
60
+ process.exit(1);
61
+ }
62
+ // Validate: if slackToken is provided, slackChannelId must also be provided
63
+ if (parsed.slackToken && !parsed.slackChannelId) {
64
+ console.error("Error: --slackChannelId is required when --slackToken is provided");
65
+ process.exit(1);
66
+ }
67
+ return parsed;
68
+ };
69
+ const main = async () => {
70
+ try {
71
+ const { before, after, projectId, token, openaiToken, slackToken, slackChannelId, } = parseArgs();
72
+ console.log(`Fetching diff between ${before} and ${after}...`);
73
+ const result = await (0, getDiff_1.getDiff)(before, after, projectId, token);
74
+ // Filter assets and sanitize diffs
75
+ const filteredDiffs = filterAssetDiffs(result.diffs);
76
+ const sanitizedDiffs = (0, dataSanitizer_1.sanitizeDiffs)(filteredDiffs);
77
+ // Create sanitized data for prompt preparation
78
+ const sanitizedData = {
79
+ ...result,
80
+ diffs: sanitizedDiffs,
81
+ };
82
+ // Prepare prompts
83
+ const systemPrompt = (0, promptInstructions_1.getSystemPrompt)();
84
+ const userPrompt = (0, promptInstructions_1.prepareUserPrompt)(sanitizedData);
85
+ // Estimate token usage (include diffs only for code files)
86
+ const codeDiffs = sanitizedDiffs.filter((diff) => (0, promptInstructions_1.shouldIncludeDiff)(diff.old_path) && diff.diff);
87
+ // Create a modified result with only code file diffs for token estimation
88
+ const codeDiffsResult = {
89
+ ...result,
90
+ diffs: codeDiffs,
91
+ };
92
+ const tokenEstimate = (0, tokenEstimator_1.estimateTokenUsage)(codeDiffsResult, {
93
+ includeDiffs: true, // Include diffs for code files
94
+ includeSystemPrompt: true,
95
+ systemPrompt: systemPrompt,
96
+ filterAssets: true,
97
+ });
98
+ // Add user prompt tokens
99
+ const userPromptTokens = Math.ceil(userPrompt.length / 4);
100
+ const totalInputTokens = tokenEstimate.inputTokens + userPromptTokens;
101
+ const estimatedOutputTokens = Math.ceil(totalInputTokens * 0.25);
102
+ const totalTokens = totalInputTokens + estimatedOutputTokens;
103
+ // Display token estimate
104
+ console.log("\nToken input and output estimate:");
105
+ console.log(` Input: ${totalInputTokens.toLocaleString()} tokens`);
106
+ console.log(` Output: ${estimatedOutputTokens.toLocaleString()} tokens`);
107
+ console.log(` Total: ${totalTokens.toLocaleString()} tokens`);
108
+ console.log(`\nEstimated cost: $${(0, tokenEstimator_1.estimateCost)(totalTokens, "gpt-4o-mini").toFixed(6)}`);
109
+ // Call OpenAI API
110
+ console.log("\nGenerating release notes...");
111
+ const { content, usage } = await (0, openaiClient_1.generateReleaseNotes)(systemPrompt, userPrompt, openaiToken);
112
+ // Display actual token usage if available
113
+ if (usage) {
114
+ console.log("\nActual token usage:");
115
+ console.log(` Input: ${usage.prompt_tokens.toLocaleString()} tokens`);
116
+ console.log(` Output: ${usage.completion_tokens.toLocaleString()} tokens`);
117
+ console.log(` Total: ${usage.total_tokens.toLocaleString()} tokens`);
118
+ const actualCost = (0, tokenEstimator_1.estimateCost)(usage.total_tokens, "gpt-4o-mini");
119
+ console.log(`\nActual cost: $${actualCost.toFixed(6)}`);
120
+ }
121
+ // Display release notes
122
+ console.log("\n=== Release Notes ===\n");
123
+ console.log(content);
124
+ // Send to Slack if token and channel ID are provided
125
+ if (slackToken && slackChannelId) {
126
+ try {
127
+ console.log("\nSending release notes to Slack...");
128
+ await (0, slackClient_1.sendSlackMessage)(slackToken, slackChannelId, content);
129
+ console.log("✓ Release notes sent to Slack successfully");
130
+ }
131
+ catch (slackError) {
132
+ console.warn(`\n⚠ Warning: Failed to send release notes to Slack: ${slackError instanceof Error ? slackError.message : String(slackError)}`);
133
+ // Don't fail the command - GitLab + LLM parts succeeded
134
+ }
135
+ }
136
+ }
137
+ catch (error) {
138
+ console.error("Error:", error instanceof Error ? error.message : String(error));
139
+ process.exit(1);
140
+ }
141
+ };
142
+ main();
143
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { GitLabDiff } from "./types";
2
+ /**
3
+ * Sanitized diff type without unnecessary fields
4
+ */
5
+ export interface SanitizedDiff {
6
+ old_path: string;
7
+ new_path: string;
8
+ diff: string;
9
+ new_file: boolean;
10
+ renamed_file: boolean;
11
+ deleted_file: boolean;
12
+ }
13
+ /**
14
+ * Sanitizes diff data by removing unnecessary fields
15
+ * Removes: collapsed, too_large, a_mode, b_mode, generated_file
16
+ */
17
+ export declare const sanitizeDiff: (diff: GitLabDiff) => SanitizedDiff;
18
+ /**
19
+ * Sanitizes an array of diffs
20
+ */
21
+ export declare const sanitizeDiffs: (diffs: GitLabDiff[]) => SanitizedDiff[];
22
+ //# sourceMappingURL=dataSanitizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataSanitizer.d.ts","sourceRoot":"","sources":["../src/dataSanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,UAAU,KAAG,aAS/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,UAAU,EAAE,KAAG,aAAa,EAEhE,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeDiffs = exports.sanitizeDiff = void 0;
4
+ /**
5
+ * Sanitizes diff data by removing unnecessary fields
6
+ * Removes: collapsed, too_large, a_mode, b_mode, generated_file
7
+ */
8
+ const sanitizeDiff = (diff) => {
9
+ return {
10
+ old_path: diff.old_path,
11
+ new_path: diff.new_path,
12
+ diff: diff.diff,
13
+ new_file: diff.new_file,
14
+ renamed_file: diff.renamed_file,
15
+ deleted_file: diff.deleted_file,
16
+ };
17
+ };
18
+ exports.sanitizeDiff = sanitizeDiff;
19
+ /**
20
+ * Sanitizes an array of diffs
21
+ */
22
+ const sanitizeDiffs = (diffs) => {
23
+ return diffs.map(exports.sanitizeDiff);
24
+ };
25
+ exports.sanitizeDiffs = sanitizeDiffs;
26
+ //# sourceMappingURL=dataSanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataSanitizer.js","sourceRoot":"","sources":["../src/dataSanitizer.ts"],"names":[],"mappings":";;;AAcA;;;GAGG;AACI,MAAM,YAAY,GAAG,CAAC,IAAgB,EAAiB,EAAE;IAC9D,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC;AACJ,CAAC,CAAC;AATW,QAAA,YAAY,gBASvB;AAEF;;GAEG;AACI,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAmB,EAAE;IACpE,OAAO,KAAK,CAAC,GAAG,CAAC,oBAAY,CAAC,CAAC;AACjC,CAAC,CAAC;AAFW,QAAA,aAAa,iBAExB"}
@@ -0,0 +1,4 @@
1
+ import { GitLabCompareResponse } from "./types";
2
+ export declare const verifyTokenAccess: (projectId: string, token: string) => Promise<void>;
3
+ export declare const getDiff: (beforeHash: string, afterHash: string, projectId: string, token: string) => Promise<GitLabCompareResponse>;
4
+ //# sourceMappingURL=getDiff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDiff.d.ts","sourceRoot":"","sources":["../src/getDiff.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAc,MAAM,SAAS,CAAC;AAI5D,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,OAAO,MAAM,KACZ,OAAO,CAAC,IAAI,CAqBd,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,OAAO,MAAM,KACZ,OAAO,CAAC,qBAAqB,CAsJ/B,CAAC"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getDiff = exports.verifyTokenAccess = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const GITLAB_API_BASE_URL = "https://gitlab.com/api/v4";
9
+ const verifyTokenAccess = async (projectId, token) => {
10
+ const apiClient = axios_1.default.create({
11
+ baseURL: GITLAB_API_BASE_URL,
12
+ headers: {
13
+ "PRIVATE-TOKEN": token,
14
+ },
15
+ });
16
+ try {
17
+ await apiClient.get(`/projects/${encodeURIComponent(projectId)}`);
18
+ }
19
+ catch (error) {
20
+ if (axios_1.default.isAxiosError(error) && error.response?.status === 403) {
21
+ throw new Error(`Token doesn't have access to project ${projectId}. Please verify:
22
+ 1. Token has 'api' scope enabled
23
+ 2. Token has access to this project
24
+ 3. Project ID is correct`);
25
+ }
26
+ throw error;
27
+ }
28
+ };
29
+ exports.verifyTokenAccess = verifyTokenAccess;
30
+ const getDiff = async (beforeHash, afterHash, projectId, token) => {
31
+ const apiClient = axios_1.default.create({
32
+ baseURL: GITLAB_API_BASE_URL,
33
+ headers: {
34
+ "PRIVATE-TOKEN": token,
35
+ },
36
+ });
37
+ const url = `/projects/${encodeURIComponent(projectId)}/repository/compare`;
38
+ const params = {
39
+ from: beforeHash,
40
+ to: afterHash,
41
+ };
42
+ try {
43
+ let response = await apiClient.get(url, {
44
+ params,
45
+ });
46
+ // If no diffs returned, try alternative approaches
47
+ if (response.data.diffs.length === 0 && response.data.commits.length > 0) {
48
+ const allDiffs = [];
49
+ const processedFiles = new Set();
50
+ // Strategy 1: For merge commits, compare with their first parent to get merged changes
51
+ for (const commit of response.data.commits) {
52
+ const isMergeCommit = commit.title.toLowerCase().startsWith("merge") ||
53
+ commit.parent_ids.length > 1;
54
+ if (isMergeCommit && commit.parent_ids.length > 0) {
55
+ // Compare merge commit with its first parent (main branch before merge)
56
+ try {
57
+ const mergeCompareUrl = `/projects/${encodeURIComponent(projectId)}/repository/compare`;
58
+ const mergeCompareParams = {
59
+ from: commit.parent_ids[0], // First parent (main branch)
60
+ to: commit.id, // The merge commit
61
+ };
62
+ const mergeCompareResponse = await apiClient.get(mergeCompareUrl, { params: mergeCompareParams });
63
+ // Add unique diffs from this merge
64
+ for (const diff of mergeCompareResponse.data.diffs) {
65
+ const fileKey = `${diff.old_path}-${diff.new_path}`;
66
+ if (!processedFiles.has(fileKey)) {
67
+ processedFiles.add(fileKey);
68
+ allDiffs.push(diff);
69
+ }
70
+ }
71
+ }
72
+ catch (mergeError) {
73
+ // If merge compare fails, try getting individual commit diff
74
+ try {
75
+ const commitDiffUrl = `/projects/${encodeURIComponent(projectId)}/repository/commits/${commit.id}/diff`;
76
+ const commitDiffResponse = await apiClient.get(commitDiffUrl);
77
+ for (const diff of commitDiffResponse.data) {
78
+ const fileKey = `${diff.old_path}-${diff.new_path}`;
79
+ if (!processedFiles.has(fileKey)) {
80
+ processedFiles.add(fileKey);
81
+ allDiffs.push(diff);
82
+ }
83
+ }
84
+ }
85
+ catch (commitError) {
86
+ // Skip this commit if we can't get its diff
87
+ console.warn(`Warning: Could not get diff for merge commit ${commit.short_id}`);
88
+ }
89
+ }
90
+ }
91
+ else if (!isMergeCommit) {
92
+ // Strategy 2: For non-merge commits, get their direct diff
93
+ try {
94
+ const commitDiffUrl = `/projects/${encodeURIComponent(projectId)}/repository/commits/${commit.id}/diff`;
95
+ const commitDiffResponse = await apiClient.get(commitDiffUrl);
96
+ for (const diff of commitDiffResponse.data) {
97
+ const fileKey = `${diff.old_path}-${diff.new_path}`;
98
+ if (!processedFiles.has(fileKey)) {
99
+ processedFiles.add(fileKey);
100
+ allDiffs.push(diff);
101
+ }
102
+ }
103
+ }
104
+ catch (commitError) {
105
+ console.warn(`Warning: Could not get diff for commit ${commit.short_id}`);
106
+ }
107
+ }
108
+ }
109
+ // If we found diffs, add them to the response
110
+ if (allDiffs.length > 0) {
111
+ response.data.diffs = allDiffs;
112
+ }
113
+ }
114
+ return response.data;
115
+ }
116
+ catch (error) {
117
+ if (axios_1.default.isAxiosError(error)) {
118
+ if (error.response) {
119
+ const status = error.response.status;
120
+ const statusText = error.response.statusText;
121
+ const errorData = error.response.data;
122
+ const errorMessage = errorData?.message || errorData?.error || "";
123
+ const errorDetails = errorData?.error_description || "";
124
+ let fullErrorMessage = `GitLab API error: ${status} - ${statusText}`;
125
+ if (errorMessage) {
126
+ fullErrorMessage += `\nMessage: ${errorMessage}`;
127
+ }
128
+ if (errorDetails) {
129
+ fullErrorMessage += `\nDetails: ${errorDetails}`;
130
+ }
131
+ if (status === 403) {
132
+ fullErrorMessage += `\n\nPossible causes:
133
+ - Token doesn't have 'api' or 'read_repository' scope
134
+ - Token doesn't have access to project ${projectId}
135
+ - Project might be private and token lacks permissions
136
+ - Token might be expired or invalid`;
137
+ }
138
+ if (status === 404) {
139
+ fullErrorMessage += `\n\nPossible causes:
140
+ - Project ID ${projectId} not found
141
+ - Commit hashes might be invalid
142
+ - Project might not exist or be inaccessible`;
143
+ }
144
+ throw new Error(fullErrorMessage);
145
+ }
146
+ throw new Error(`Network error: ${error.message}`);
147
+ }
148
+ throw error;
149
+ }
150
+ };
151
+ exports.getDiff = getDiff;
152
+ //# sourceMappingURL=getDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDiff.js","sourceRoot":"","sources":["../src/getDiff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ interface OpenAIResponse {
2
+ id: string;
3
+ object: string;
4
+ created: number;
5
+ model: string;
6
+ choices: Array<{
7
+ index: number;
8
+ message: {
9
+ role: string;
10
+ content: string;
11
+ };
12
+ finish_reason: string;
13
+ }>;
14
+ usage: {
15
+ prompt_tokens: number;
16
+ completion_tokens: number;
17
+ total_tokens: number;
18
+ };
19
+ }
20
+ export declare const generateReleaseNotes: (systemPrompt: string, userPrompt: string, apiKey: string) => Promise<{
21
+ content: string;
22
+ usage: OpenAIResponse["usage"];
23
+ }>;
24
+ export {};
25
+ //# sourceMappingURL=openaiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../src/openaiClient.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,eAAO,MAAM,oBAAoB,GAC/B,cAAc,MAAM,EACpB,YAAY,MAAM,EAClB,QAAQ,MAAM,KACb,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAAE,CAiC7D,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateReleaseNotes = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const generateReleaseNotes = async (systemPrompt, userPrompt, apiKey) => {
9
+ const response = await axios_1.default.post("https://api.openai.com/v1/chat/completions", {
10
+ model: "gpt-4o-mini",
11
+ messages: [
12
+ {
13
+ role: "system",
14
+ content: systemPrompt,
15
+ },
16
+ {
17
+ role: "user",
18
+ content: userPrompt,
19
+ },
20
+ ],
21
+ temperature: 0.7,
22
+ }, {
23
+ headers: {
24
+ Authorization: `Bearer ${apiKey}`,
25
+ "Content-Type": "application/json",
26
+ },
27
+ });
28
+ const content = response.data.choices[0]?.message?.content || "";
29
+ const usage = response.data.usage;
30
+ if (!content) {
31
+ throw new Error("No content received from OpenAI API");
32
+ }
33
+ return { content, usage };
34
+ };
35
+ exports.generateReleaseNotes = generateReleaseNotes;
36
+ //# sourceMappingURL=openaiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openaiClient.js","sourceRoot":"","sources":["../src/openaiClient.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAsBnB,MAAM,oBAAoB,GAAG,KAAK,EACvC,YAAoB,EACpB,UAAkB,EAClB,MAAc,EACgD,EAAE;IAChE,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAC/B,4CAA4C,EAC5C;QACE,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,YAAY;aACtB;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,UAAU;aACpB;SACF;QACD,WAAW,EAAE,GAAG;KACjB,EACD;QACE,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,EAAE;YACjC,cAAc,EAAE,kBAAkB;SACnC;KACF,CACF,CAAC;IAEF,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;IAElC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC,CAAC;AArCW,QAAA,oBAAoB,wBAqC/B"}
@@ -0,0 +1,19 @@
1
+ import { GitLabCompareResponse, GitLabCommit } from "./types";
2
+ import { SanitizedDiff } from "./dataSanitizer";
3
+ interface SanitizedCompareResponse {
4
+ commit: GitLabCommit;
5
+ commits: GitLabCommit[];
6
+ diffs: SanitizedDiff[];
7
+ compare_timeout: boolean;
8
+ compare_same_ref: boolean;
9
+ }
10
+ /**
11
+ * Determines if a file should have its diff included in the prompt
12
+ * Includes: code files (.ts, .tsx, .js, .jsx, .py, .java, etc.)
13
+ * Excludes: config files, tests, docs, etc.
14
+ */
15
+ export declare const shouldIncludeDiff: (filePath: string) => boolean;
16
+ export declare const getSystemPrompt: () => string;
17
+ export declare const prepareUserPrompt: (data: SanitizedCompareResponse | GitLabCompareResponse) => string;
18
+ export {};
19
+ //# sourceMappingURL=promptInstructions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptInstructions.d.ts","sourceRoot":"","sources":["../src/promptInstructions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,UAAU,wBAAwB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,OAyFpD,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,MAyClC,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,wBAAwB,GAAG,qBAAqB,KACrD,MAwDF,CAAC"}
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prepareUserPrompt = exports.getSystemPrompt = exports.shouldIncludeDiff = void 0;
4
+ /**
5
+ * Determines if a file should have its diff included in the prompt
6
+ * Includes: code files (.ts, .tsx, .js, .jsx, .py, .java, etc.)
7
+ * Excludes: config files, tests, docs, etc.
8
+ */
9
+ const shouldIncludeDiff = (filePath) => {
10
+ const lowerPath = filePath.toLowerCase();
11
+ // Code file extensions to include
12
+ const codeExtensions = [
13
+ ".ts",
14
+ ".tsx",
15
+ ".js",
16
+ ".jsx",
17
+ ".py",
18
+ ".java",
19
+ ".go",
20
+ ".rs",
21
+ ".cpp",
22
+ ".c",
23
+ ".cs",
24
+ ".php",
25
+ ".rb",
26
+ ".swift",
27
+ ".kt",
28
+ ".scala",
29
+ ".vue",
30
+ ".svelte",
31
+ ".css",
32
+ ".scss",
33
+ ".sass",
34
+ ".less",
35
+ ".html",
36
+ ".htm",
37
+ ];
38
+ const hasCodeExtension = codeExtensions.some((ext) => lowerPath.endsWith(ext));
39
+ // Exclude test files
40
+ const isTestFile = lowerPath.includes("/test/") ||
41
+ lowerPath.includes("/tests/") ||
42
+ lowerPath.includes("/__tests__/") ||
43
+ lowerPath.includes(".test.") ||
44
+ lowerPath.includes(".spec.") ||
45
+ lowerPath.startsWith("test/") ||
46
+ lowerPath.startsWith("tests/");
47
+ // Exclude config files
48
+ const isConfigFile = lowerPath.includes("/config/") ||
49
+ lowerPath.endsWith(".config.js") ||
50
+ lowerPath.endsWith(".config.ts") ||
51
+ lowerPath.endsWith("package.json") ||
52
+ lowerPath.endsWith("package-lock.json") ||
53
+ lowerPath.endsWith("yarn.lock") ||
54
+ lowerPath.endsWith("pnpm-lock.yaml") ||
55
+ lowerPath.endsWith(".env") ||
56
+ lowerPath.endsWith(".env.example") ||
57
+ lowerPath.includes("/.github/") ||
58
+ lowerPath.includes("/.gitlab/") ||
59
+ lowerPath.endsWith("tsconfig.json") ||
60
+ lowerPath.endsWith("jsconfig.json") ||
61
+ lowerPath.endsWith(".eslintrc") ||
62
+ lowerPath.endsWith(".prettierrc") ||
63
+ lowerPath.endsWith("tailwind.config") ||
64
+ lowerPath.endsWith("next.config") ||
65
+ lowerPath.endsWith("webpack.config") ||
66
+ lowerPath.endsWith("vite.config") ||
67
+ lowerPath.endsWith(".gitignore") ||
68
+ lowerPath.endsWith(".dockerignore") ||
69
+ lowerPath.endsWith("Dockerfile") ||
70
+ lowerPath.endsWith("docker-compose.yml") ||
71
+ lowerPath.endsWith(".md") ||
72
+ lowerPath.endsWith(".txt") ||
73
+ lowerPath.endsWith(".json") ||
74
+ lowerPath.endsWith(".yaml") ||
75
+ lowerPath.endsWith(".yml");
76
+ // Exclude documentation
77
+ const isDocumentation = lowerPath.includes("/docs/") ||
78
+ lowerPath.includes("/documentation/") ||
79
+ lowerPath.startsWith("docs/") ||
80
+ lowerPath.startsWith("documentation/") ||
81
+ lowerPath.includes("README") ||
82
+ lowerPath.includes("CHANGELOG") ||
83
+ lowerPath.includes("LICENSE");
84
+ return (hasCodeExtension && !isTestFile && !isConfigFile && !isDocumentation);
85
+ };
86
+ exports.shouldIncludeDiff = shouldIncludeDiff;
87
+ const getSystemPrompt = () => {
88
+ return `You are a technical writer specialized in creating clear, professional release notes for software projects.
89
+
90
+ Your task is to analyze Git commit data and generate well-structured release notes that are:
91
+ - Clear and concise
92
+ - Professional yet accessible
93
+ - Grouped by category (New Features, Improvements, Bug Fixes)
94
+ - Written in a consistent style
95
+ - Focused on user-facing changes when possible
96
+ - Include a few relevant emojis to make it more engaging (use sparingly, 2-4 emojis per section maximum)
97
+ - The summary must not be longer than 800 characters, if it is, you must summarize the changes into a few sentences.
98
+
99
+ Guidelines:
100
+ 1. Categorize changes into: "New Features", "Improvements", and "Bug Fixes"
101
+ 2. Use conventional commit prefixes (feat:, fix:, refactor:, etc.) to help categorize
102
+ 3. We should not take in consideration the name commits, only the changes they introduce.
103
+ 4. Write in present tense and active voice
104
+ 5. Be specific but concise - avoid vague descriptions
105
+ 6. Group related changes together
106
+ 7. If a commit message is unclear, infer the change from file paths and context
107
+ 8. Skip trivial changes unless they're user-facing
108
+ 9. Use markdown formatting for the output
109
+ 10. Start with a brief summary if there are significant changes
110
+ 11. Add a few relevant emojis (sparingly) - use emojis that match the content (e.g., ✨ for new features, 🐛 for bug fixes, ⚡ for improvements)
111
+ 12. IMPORTANT: Only include sections that have items. If there are no bug fixes, improvements, or features in a category, do NOT include that section at all. Never write placeholder text like "No specific bug fixes were reported" or similar.
112
+
113
+ Output format:
114
+ Use markdown with clear sections. Only include sections that have content. Example structure:
115
+ ## Summary
116
+ [Brief overview if significant changes]
117
+
118
+ ## New Features ✨
119
+ - [Feature description]
120
+
121
+ ## Improvements ⚡
122
+ - [Improvement description]
123
+
124
+ ## Bug Fixes 🐛
125
+ - [Bug fix description]
126
+
127
+ Note: If a category has no items, omit that entire section completely.`;
128
+ };
129
+ exports.getSystemPrompt = getSystemPrompt;
130
+ const prepareUserPrompt = (data) => {
131
+ const commitsText = data.commits
132
+ .map((commit) => {
133
+ return `Commit: ${commit.title}
134
+ Message: ${commit.message}
135
+ Author: ${commit.author_name}
136
+ Date: ${commit.committed_date}
137
+ Hash: ${commit.short_id}`;
138
+ })
139
+ .join("\n\n");
140
+ // Separate files with and without diffs
141
+ const filesWithDiffs = [];
142
+ const filesWithoutDiffs = [];
143
+ data.diffs.forEach((diff) => {
144
+ const status = diff.new_file
145
+ ? "NEW"
146
+ : diff.deleted_file
147
+ ? "DELETED"
148
+ : diff.renamed_file
149
+ ? "RENAMED"
150
+ : "MODIFIED";
151
+ const filePath = diff.old_path !== diff.new_path
152
+ ? `${diff.old_path} -> ${diff.new_path}`
153
+ : diff.old_path;
154
+ if ((0, exports.shouldIncludeDiff)(diff.old_path) && diff.diff) {
155
+ // Include diff for code files
156
+ filesWithDiffs.push(`${status}: ${filePath}\n\`\`\`diff\n${diff.diff}\n\`\`\``);
157
+ }
158
+ else {
159
+ // Just file path for non-code files
160
+ filesWithoutDiffs.push(`${status}: ${filePath}`);
161
+ }
162
+ });
163
+ let filesText = "";
164
+ if (filesWithDiffs.length > 0) {
165
+ filesText += "Files Changed (with code diffs):\n";
166
+ filesText += filesWithDiffs.join("\n\n");
167
+ }
168
+ if (filesWithoutDiffs.length > 0) {
169
+ if (filesText)
170
+ filesText += "\n\n";
171
+ filesText += "Other Files Changed:\n";
172
+ filesText += filesWithoutDiffs.join("\n");
173
+ }
174
+ return `Analyze the following Git commits and file changes, then generate release notes in the requested format.
175
+
176
+ Commits:
177
+ ${commitsText}
178
+
179
+ ${filesText}
180
+
181
+ Please generate release notes based on this information.`;
182
+ };
183
+ exports.prepareUserPrompt = prepareUserPrompt;
184
+ //# sourceMappingURL=promptInstructions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptInstructions.js","sourceRoot":"","sources":["../src/promptInstructions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const sendSlackMessage: (slackToken: string, channelId: string, markdownText: string) => Promise<void>;
2
+ //# sourceMappingURL=slackClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slackClient.d.ts","sourceRoot":"","sources":["../src/slackClient.ts"],"names":[],"mappings":"AAyGA,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,cAAc,MAAM,KACnB,OAAO,CAAC,IAAI,CAwCd,CAAC"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sendSlackMessage = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ /**
9
+ * Converts markdown release notes to Slack Block Kit format
10
+ */
11
+ const convertMarkdownToSlackBlocks = (markdown) => {
12
+ const blocks = [];
13
+ const lines = markdown.split("\n");
14
+ let currentSection = [];
15
+ let currentSectionTitle = "";
16
+ const flushSection = () => {
17
+ if (currentSection.length > 0) {
18
+ // Add divider before new section (except first)
19
+ if (blocks.length > 0) {
20
+ blocks.push({ type: "divider" });
21
+ }
22
+ // Add section header
23
+ if (currentSectionTitle) {
24
+ blocks.push({
25
+ type: "header",
26
+ text: {
27
+ type: "plain_text",
28
+ text: currentSectionTitle.replace(/^##\s*/, "").trim(),
29
+ },
30
+ });
31
+ }
32
+ // Add section content
33
+ const content = currentSection.join("\n").trim();
34
+ if (content) {
35
+ blocks.push({
36
+ type: "section",
37
+ text: {
38
+ type: "mrkdwn",
39
+ text: content,
40
+ },
41
+ });
42
+ }
43
+ currentSection = [];
44
+ currentSectionTitle = "";
45
+ }
46
+ };
47
+ for (const line of lines) {
48
+ const trimmed = line.trim();
49
+ // Check for section headers (##)
50
+ if (trimmed.startsWith("##")) {
51
+ flushSection();
52
+ currentSectionTitle = trimmed;
53
+ continue;
54
+ }
55
+ // Skip empty lines at the start
56
+ if (trimmed === "" && currentSection.length === 0) {
57
+ continue;
58
+ }
59
+ // Convert markdown to Slack mrkdwn format
60
+ let slackLine = trimmed;
61
+ // Convert markdown bold **text** to Slack bold *text*
62
+ slackLine = slackLine.replace(/\*\*(.+?)\*\*/g, "*$1*");
63
+ // Convert markdown code `text` to Slack code `text` (same)
64
+ // Already compatible
65
+ // Convert markdown list items (- or *) to Slack list format
66
+ if (slackLine.match(/^[-*]\s+/)) {
67
+ slackLine = slackLine.replace(/^[-*]\s+/, "• ");
68
+ }
69
+ currentSection.push(slackLine);
70
+ }
71
+ // Flush remaining section
72
+ flushSection();
73
+ return blocks;
74
+ };
75
+ const sendSlackMessage = async (slackToken, channelId, markdownText) => {
76
+ try {
77
+ // Convert markdown to Slack Block Kit format
78
+ const blocks = convertMarkdownToSlackBlocks(markdownText);
79
+ // Fallback text for notifications
80
+ const fallbackText = markdownText
81
+ .replace(/##\s*/g, "")
82
+ .replace(/\*\*(.+?)\*\*/g, "$1")
83
+ .substring(0, 200);
84
+ const response = await axios_1.default.post("https://slack.com/api/chat.postMessage", {
85
+ channel: channelId,
86
+ text: fallbackText,
87
+ blocks: blocks,
88
+ }, {
89
+ headers: {
90
+ Authorization: `Bearer ${slackToken}`,
91
+ "Content-Type": "application/json",
92
+ },
93
+ });
94
+ if (!response.data.ok) {
95
+ throw new Error(response.data.error || "Unknown error from Slack API");
96
+ }
97
+ }
98
+ catch (error) {
99
+ if (axios_1.default.isAxiosError(error)) {
100
+ if (error.response?.data?.error) {
101
+ throw new Error(`Slack API error: ${error.response.data.error}`);
102
+ }
103
+ throw new Error(`Network error: ${error.message}`);
104
+ }
105
+ throw error;
106
+ }
107
+ };
108
+ exports.sendSlackMessage = sendSlackMessage;
109
+ //# sourceMappingURL=slackClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slackClient.js","sourceRoot":"","sources":["../src/slackClient.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAsB1B;;GAEG;AACH,MAAM,4BAA4B,GAAG,CAAC,QAAgB,EAAgB,EAAE;IACtE,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,cAAc,GAAa,EAAE,CAAC;IAClC,IAAI,mBAAmB,GAAG,EAAE,CAAC;IAE7B,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,gDAAgD;YAChD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YACnC,CAAC;YAED,qBAAqB;YACrB,IAAI,mBAAmB,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE;wBACJ,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;qBACvD;iBACF,CAAC,CAAC;YACL,CAAC;YAED,sBAAsB;YACtB,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,SAAS;oBACb,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,OAAO;qBACd;iBACF,CAAC,CAAC;YACL,CAAC;YAED,cAAc,GAAG,EAAE,CAAC;YACpB,mBAAmB,GAAG,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,iCAAiC;QACjC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,YAAY,EAAE,CAAC;YACf,mBAAmB,GAAG,OAAO,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,gCAAgC;QAChC,IAAI,OAAO,KAAK,EAAE,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,SAAS;QACX,CAAC;QAED,0CAA0C;QAC1C,IAAI,SAAS,GAAG,OAAO,CAAC;QAExB,sDAAsD;QACtD,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;QAExD,2DAA2D;QAC3D,qBAAqB;QAErB,4DAA4D;QAC5D,IAAI,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAChC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,0BAA0B;IAC1B,YAAY,EAAE,CAAC;IAEf,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEK,MAAM,gBAAgB,GAAG,KAAK,EACnC,UAAkB,EAClB,SAAiB,EACjB,YAAoB,EACL,EAAE;IACjB,IAAI,CAAC;QACH,6CAA6C;QAC7C,MAAM,MAAM,GAAG,4BAA4B,CAAC,YAAY,CAAC,CAAC;QAE1D,kCAAkC;QAClC,MAAM,YAAY,GAAG,YAAY;aAC9B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;aACrB,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC;aAC/B,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAErB,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAC/B,wCAAwC,EACxC;YACE,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,MAAM;SACf,EACD;YACE,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,UAAU,EAAE;gBACrC,cAAc,EAAE,kBAAkB;aACnC;SACF,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,8BAA8B,CACtD,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,eAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AA5CW,QAAA,gBAAgB,oBA4C3B"}
@@ -0,0 +1,37 @@
1
+ import { GitLabCompareResponse } from "./types";
2
+ interface TokenEstimate {
3
+ totalTokens: number;
4
+ inputTokens: number;
5
+ estimatedOutputTokens: number;
6
+ breakdown: {
7
+ commits: number;
8
+ filePaths: number;
9
+ diffs: number;
10
+ systemPrompt?: number;
11
+ };
12
+ }
13
+ /**
14
+ * Estimates token usage for LLM API calls based on GitLab compare response
15
+ * @param data - The GitLab compare response data
16
+ * @param options - Configuration options
17
+ * @returns Token estimate breakdown
18
+ */
19
+ export declare const estimateTokenUsage: (data: GitLabCompareResponse, options?: {
20
+ includeDiffs?: boolean;
21
+ includeSystemPrompt?: boolean;
22
+ systemPrompt?: string;
23
+ filterAssets?: boolean;
24
+ }) => TokenEstimate;
25
+ /**
26
+ * Formats token estimate for display
27
+ */
28
+ export declare const formatTokenEstimate: (estimate: TokenEstimate) => string;
29
+ /**
30
+ * Estimates cost based on token count and model pricing
31
+ * @param tokens - Number of tokens
32
+ * @param model - Model name (default: gpt-4o-mini)
33
+ * @returns Cost estimate in USD
34
+ */
35
+ export declare const estimateCost: (tokens: number, model?: "gpt-4o-mini" | "gpt-4o" | "deepseek-chat" | "custom") => number;
36
+ export {};
37
+ //# sourceMappingURL=tokenEstimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenEstimator.d.ts","sourceRoot":"","sources":["../src/tokenEstimator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAc,MAAM,SAAS,CAAC;AAE5D,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAwDD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,qBAAqB,EAC3B,UAAS;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACnB,KACL,aA0DF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,aAAa,KAAG,MAc7D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,MAAM,EACd,QAAO,aAAa,GAAG,QAAQ,GAAG,eAAe,GAAG,QAAwB,KAC3E,MAkCF,CAAC"}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateCost = exports.formatTokenEstimate = exports.estimateTokenUsage = void 0;
4
+ /**
5
+ * Estimates token count using a simple approximation:
6
+ * - For English text: ~1 token per 4 characters
7
+ * - This is a rough estimate that works reasonably well for most LLMs
8
+ */
9
+ const estimateTokens = (text) => {
10
+ // Rough approximation: 1 token ≈ 4 characters for English text
11
+ // This is a conservative estimate that works for most tokenizers
12
+ return Math.ceil(text.length / 4);
13
+ };
14
+ const isAssetFile = (filePath) => {
15
+ const lowerPath = filePath.toLowerCase();
16
+ const assetExtensions = [
17
+ ".svg",
18
+ ".png",
19
+ ".jpg",
20
+ ".jpeg",
21
+ ".gif",
22
+ ".webp",
23
+ ".ico",
24
+ ".bmp",
25
+ ".tiff",
26
+ ".woff",
27
+ ".woff2",
28
+ ".ttf",
29
+ ".eot",
30
+ ".otf",
31
+ ];
32
+ const hasAssetExtension = assetExtensions.some((ext) => lowerPath.endsWith(ext));
33
+ const isInAssetDirectory = lowerPath.includes("/assets/") ||
34
+ lowerPath.includes("/images/") ||
35
+ lowerPath.includes("/public/") ||
36
+ lowerPath.includes("/static/") ||
37
+ lowerPath.startsWith("assets/") ||
38
+ lowerPath.startsWith("images/") ||
39
+ lowerPath.startsWith("public/") ||
40
+ lowerPath.startsWith("static/");
41
+ return hasAssetExtension || isInAssetDirectory;
42
+ };
43
+ const filterAssetDiffs = (diffs) => {
44
+ return diffs.filter((diff) => !isAssetFile(diff.old_path) && !isAssetFile(diff.new_path));
45
+ };
46
+ /**
47
+ * Estimates token usage for LLM API calls based on GitLab compare response
48
+ * @param data - The GitLab compare response data
49
+ * @param options - Configuration options
50
+ * @returns Token estimate breakdown
51
+ */
52
+ const estimateTokenUsage = (data, options = {}) => {
53
+ const { includeDiffs = false, includeSystemPrompt = false, systemPrompt = "", filterAssets = true, } = options;
54
+ let commitsTokens = 0;
55
+ let filePathsTokens = 0;
56
+ let diffsTokens = 0;
57
+ let systemPromptTokens = 0;
58
+ // Estimate tokens from commits
59
+ for (const commit of data.commits) {
60
+ // Include commit message, title, author
61
+ const commitText = `${commit.title}\n${commit.message}\n${commit.author_name}`;
62
+ commitsTokens += estimateTokens(commitText);
63
+ }
64
+ // Estimate tokens from file paths
65
+ const diffsToProcess = filterAssets ? filterAssetDiffs(data.diffs) : data.diffs;
66
+ for (const diff of diffsToProcess) {
67
+ const filePathText = `${diff.old_path} -> ${diff.new_path}`;
68
+ filePathsTokens += estimateTokens(filePathText);
69
+ }
70
+ // Estimate tokens from diffs (if included)
71
+ if (includeDiffs) {
72
+ for (const diff of diffsToProcess) {
73
+ diffsTokens += estimateTokens(diff.diff);
74
+ }
75
+ }
76
+ // Estimate system prompt tokens
77
+ if (includeSystemPrompt && systemPrompt) {
78
+ systemPromptTokens = estimateTokens(systemPrompt);
79
+ }
80
+ const inputTokens = commitsTokens + filePathsTokens + diffsTokens + systemPromptTokens;
81
+ // Estimate output tokens (typically 20-30% of input for summaries)
82
+ // This is a rough estimate - actual output depends on the prompt
83
+ const estimatedOutputTokens = Math.ceil(inputTokens * 0.25);
84
+ return {
85
+ totalTokens: inputTokens + estimatedOutputTokens,
86
+ inputTokens,
87
+ estimatedOutputTokens,
88
+ breakdown: {
89
+ commits: commitsTokens,
90
+ filePaths: filePathsTokens,
91
+ diffs: diffsTokens,
92
+ ...(includeSystemPrompt && { systemPrompt: systemPromptTokens }),
93
+ },
94
+ };
95
+ };
96
+ exports.estimateTokenUsage = estimateTokenUsage;
97
+ /**
98
+ * Formats token estimate for display
99
+ */
100
+ const formatTokenEstimate = (estimate) => {
101
+ const breakdown = Object.entries(estimate.breakdown)
102
+ .map(([key, value]) => ` - ${key}: ${value.toLocaleString()} tokens`)
103
+ .join("\n");
104
+ return `
105
+ Token Usage Estimate:
106
+ Total: ${estimate.totalTokens.toLocaleString()} tokens
107
+ Input: ${estimate.inputTokens.toLocaleString()} tokens
108
+ Estimated Output: ${estimate.estimatedOutputTokens.toLocaleString()} tokens
109
+
110
+ Breakdown:
111
+ ${breakdown}
112
+ `;
113
+ };
114
+ exports.formatTokenEstimate = formatTokenEstimate;
115
+ /**
116
+ * Estimates cost based on token count and model pricing
117
+ * @param tokens - Number of tokens
118
+ * @param model - Model name (default: gpt-4o-mini)
119
+ * @returns Cost estimate in USD
120
+ */
121
+ const estimateCost = (tokens, model = "gpt-4o-mini") => {
122
+ // Pricing per 1M tokens (as of common pricing models)
123
+ const pricing = {
124
+ "gpt-4o-mini": {
125
+ input: 0.15, // $0.15 per 1M input tokens
126
+ output: 0.6, // $0.60 per 1M output tokens
127
+ },
128
+ "gpt-4o": {
129
+ input: 2.5, // $2.50 per 1M input tokens
130
+ output: 10.0, // $10.00 per 1M output tokens
131
+ },
132
+ "deepseek-chat": {
133
+ input: 0.14, // $0.14 per 1M input tokens
134
+ output: 0.28, // $0.28 per 1M output tokens
135
+ },
136
+ custom: {
137
+ input: 0,
138
+ output: 0,
139
+ },
140
+ };
141
+ const modelPricing = pricing[model];
142
+ if (!modelPricing) {
143
+ return 0;
144
+ }
145
+ // Rough split: 80% input, 20% output (typical for summarization)
146
+ const inputTokens = tokens * 0.8;
147
+ const outputTokens = tokens * 0.2;
148
+ const inputCost = (inputTokens / 1000000) * modelPricing.input;
149
+ const outputCost = (outputTokens / 1000000) * modelPricing.output;
150
+ return inputCost + outputCost;
151
+ };
152
+ exports.estimateCost = estimateCost;
153
+ //# sourceMappingURL=tokenEstimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenEstimator.js","sourceRoot":"","sources":["../src/tokenEstimator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface GitLabCommit {
2
+ id: string;
3
+ short_id: string;
4
+ title: string;
5
+ author_name: string;
6
+ author_email: string;
7
+ authored_date: string;
8
+ committer_name: string;
9
+ committer_email: string;
10
+ committed_date: string;
11
+ created_at: string;
12
+ message: string;
13
+ parent_ids: string[];
14
+ }
15
+ export interface GitLabDiff {
16
+ old_path: string;
17
+ new_path: string;
18
+ a_mode: string;
19
+ b_mode: string;
20
+ diff: string;
21
+ new_file: boolean;
22
+ renamed_file: boolean;
23
+ deleted_file: boolean;
24
+ }
25
+ export interface GitLabCompareResponse {
26
+ commit: GitLabCommit;
27
+ commits: GitLabCommit[];
28
+ diffs: GitLabDiff[];
29
+ compare_timeout: boolean;
30
+ compare_same_ref: boolean;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;CAC3B"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@litebox-packages/release-notes-bot",
3
+ "version": "1.2.0",
4
+ "description": "Automated release notes generator using GitLab API and OpenAI",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "release-notes-bot": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "ts-node src/cli.ts",
16
+ "start": "node dist/cli.js",
17
+ "prepublishOnly": "pnpm build"
18
+ },
19
+ "keywords": [
20
+ "gitlab",
21
+ "release-notes",
22
+ "changelog",
23
+ "automation",
24
+ "openai",
25
+ "slack"
26
+ ],
27
+ "author": "Litebox",
28
+ "license": "ISC",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "axios": "^1.6.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.10.0",
37
+ "ts-node": "^10.9.2",
38
+ "typescript": "^5.3.3"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ }
43
+ }