@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 +87 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +143 -0
- package/dist/cli.js.map +1 -0
- package/dist/dataSanitizer.d.ts +22 -0
- package/dist/dataSanitizer.d.ts.map +1 -0
- package/dist/dataSanitizer.js +26 -0
- package/dist/dataSanitizer.js.map +1 -0
- package/dist/getDiff.d.ts +4 -0
- package/dist/getDiff.d.ts.map +1 -0
- package/dist/getDiff.js +152 -0
- package/dist/getDiff.js.map +1 -0
- package/dist/openaiClient.d.ts +25 -0
- package/dist/openaiClient.d.ts.map +1 -0
- package/dist/openaiClient.js +36 -0
- package/dist/openaiClient.js.map +1 -0
- package/dist/promptInstructions.d.ts +19 -0
- package/dist/promptInstructions.d.ts.map +1 -0
- package/dist/promptInstructions.js +184 -0
- package/dist/promptInstructions.js.map +1 -0
- package/dist/slackClient.d.ts +2 -0
- package/dist/slackClient.d.ts.map +1 -0
- package/dist/slackClient.js +109 -0
- package/dist/slackClient.js.map +1 -0
- package/dist/tokenEstimator.d.ts +37 -0
- package/dist/tokenEstimator.d.ts.map +1 -0
- package/dist/tokenEstimator.js +153 -0
- package/dist/tokenEstimator.js.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
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 @@
|
|
|
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
|
package/dist/cli.js.map
ADDED
|
@@ -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"}
|
package/dist/getDiff.js
ADDED
|
@@ -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 @@
|
|
|
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":"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"}
|
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|