@releasehub/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/commands/ai.d.ts +3 -0
  2. package/dist/commands/ai.d.ts.map +1 -0
  3. package/dist/commands/ai.js +215 -0
  4. package/dist/commands/ai.js.map +1 -0
  5. package/dist/commands/auth.d.ts +3 -0
  6. package/dist/commands/auth.d.ts.map +1 -0
  7. package/dist/commands/auth.js +130 -0
  8. package/dist/commands/auth.js.map +1 -0
  9. package/dist/commands/generate.d.ts +12 -0
  10. package/dist/commands/generate.d.ts.map +1 -0
  11. package/dist/commands/generate.js +105 -0
  12. package/dist/commands/generate.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +33 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lib/ai.d.ts +15 -0
  18. package/dist/lib/ai.d.ts.map +1 -0
  19. package/dist/lib/ai.js +128 -0
  20. package/dist/lib/ai.js.map +1 -0
  21. package/dist/lib/config.d.ts +21 -0
  22. package/dist/lib/config.d.ts.map +1 -0
  23. package/dist/lib/config.js +69 -0
  24. package/dist/lib/config.js.map +1 -0
  25. package/dist/lib/errors.d.ts +15 -0
  26. package/dist/lib/errors.d.ts.map +1 -0
  27. package/dist/lib/errors.js +49 -0
  28. package/dist/lib/errors.js.map +1 -0
  29. package/dist/lib/formatters.d.ts +12 -0
  30. package/dist/lib/formatters.d.ts.map +1 -0
  31. package/dist/lib/formatters.js +121 -0
  32. package/dist/lib/formatters.js.map +1 -0
  33. package/dist/lib/git.d.ts +13 -0
  34. package/dist/lib/git.d.ts.map +1 -0
  35. package/dist/lib/git.js +52 -0
  36. package/dist/lib/git.js.map +1 -0
  37. package/dist/lib/github.d.ts +34 -0
  38. package/dist/lib/github.d.ts.map +1 -0
  39. package/dist/lib/github.js +166 -0
  40. package/dist/lib/github.js.map +1 -0
  41. package/package.json +44 -0
@@ -0,0 +1,166 @@
1
+ import { Octokit } from '@octokit/rest';
2
+ import { AuthError, ApiError } from './errors.js';
3
+ import { getGitHubToken } from './config.js';
4
+ function getOctokit() {
5
+ const token = getGitHubToken();
6
+ if (!token)
7
+ throw new AuthError('No GitHub token found. Run: releasehub auth login');
8
+ return new Octokit({ auth: token, request: { fetch } });
9
+ }
10
+ /**
11
+ * Extract linked issue numbers from PR body text.
12
+ * Matches: "Closes #123", "Fixes #456", "Resolves #789"
13
+ */
14
+ function extractLinkedIssues(body) {
15
+ if (!body)
16
+ return [];
17
+ const matches = body.matchAll(/(?:closes?|fixes?|resolves?)\s+#(\d+)/gi);
18
+ return [...matches].map(m => `#${m[1]}`);
19
+ }
20
+ /**
21
+ * Fetch all tags for a repo, sorted by date descending.
22
+ */
23
+ export async function fetchTags(repo) {
24
+ const octokit = getOctokit();
25
+ try {
26
+ const tags = [];
27
+ const iterator = octokit.paginate.iterator(octokit.rest.repos.listTags, {
28
+ owner: repo.owner,
29
+ repo: repo.name,
30
+ per_page: 100,
31
+ });
32
+ for await (const { data } of iterator) {
33
+ for (const tag of data) {
34
+ // Fetch commit date for each tag
35
+ let date = null;
36
+ try {
37
+ const { data: commit } = await octokit.rest.git.getCommit({
38
+ owner: repo.owner,
39
+ repo: repo.name,
40
+ commit_sha: tag.commit.sha,
41
+ });
42
+ date = commit.author.date;
43
+ }
44
+ catch {
45
+ // ignore — date is optional
46
+ }
47
+ tags.push({ name: tag.name, sha: tag.commit.sha, date });
48
+ }
49
+ }
50
+ return tags;
51
+ }
52
+ catch (err) {
53
+ if (err && typeof err === 'object' && 'status' in err) {
54
+ const status = err.status;
55
+ if (status === 401)
56
+ throw new AuthError('GitHub token is invalid or expired. Run: releasehub auth login');
57
+ if (status === 404)
58
+ throw new ApiError(`Repository ${repo.owner}/${repo.name} not found.`, 404);
59
+ if (status === 403)
60
+ throw new ApiError('GitHub API rate limit exceeded. Wait a moment and try again.', 403);
61
+ }
62
+ throw err;
63
+ }
64
+ }
65
+ /**
66
+ * Fetch merged PRs between two tags.
67
+ */
68
+ export async function fetchPullRequests(repo, fromTag, toTag) {
69
+ const octokit = getOctokit();
70
+ try {
71
+ // Compare the two tags to get the list of commits
72
+ const { data: comparison } = await octokit.rest.repos.compareCommits({
73
+ owner: repo.owner,
74
+ repo: repo.name,
75
+ base: fromTag,
76
+ head: toTag,
77
+ });
78
+ if (comparison.commits.length === 0)
79
+ return [];
80
+ // Collect commit SHAs in the range
81
+ const commitShas = new Set(comparison.commits.map(c => c.sha));
82
+ // Fetch merged PRs and filter to those whose merge commit is in range
83
+ const prs = [];
84
+ const iterator = octokit.paginate.iterator(octokit.rest.pulls.list, {
85
+ owner: repo.owner,
86
+ repo: repo.name,
87
+ state: 'closed',
88
+ per_page: 100,
89
+ sort: 'updated',
90
+ direction: 'desc',
91
+ });
92
+ for await (const { data } of iterator) {
93
+ for (const pr of data) {
94
+ if (!pr.merged_at)
95
+ continue;
96
+ if (!pr.merge_commit_sha)
97
+ continue;
98
+ if (!commitShas.has(pr.merge_commit_sha))
99
+ continue;
100
+ prs.push({
101
+ number: pr.number,
102
+ title: pr.title,
103
+ body: pr.body ?? null,
104
+ labels: pr.labels.map(l => (typeof l === 'string' ? l : l.name ?? '')),
105
+ author: pr.user?.login ?? 'unknown',
106
+ merged_at: pr.merged_at,
107
+ url: pr.html_url,
108
+ linked_issues: extractLinkedIssues(pr.body ?? null),
109
+ });
110
+ }
111
+ // Stop paginating once PRs are older than the from-tag comparison window
112
+ const oldest = data[data.length - 1];
113
+ if (oldest && comparison.commits[0]) {
114
+ const oldestDate = new Date(oldest.updated_at).getTime();
115
+ const baseDate = new Date(comparison.commits[0].commit.committer?.date ?? 0).getTime();
116
+ if (oldestDate < baseDate - 7 * 24 * 60 * 60 * 1000)
117
+ break;
118
+ }
119
+ }
120
+ // Sort by merged_at ascending
121
+ return prs.sort((a, b) => new Date(a.merged_at).getTime() - new Date(b.merged_at).getTime());
122
+ }
123
+ catch (err) {
124
+ if (err && typeof err === 'object' && 'status' in err) {
125
+ const status = err.status;
126
+ if (status === 401)
127
+ throw new AuthError('GitHub token is invalid or expired. Run: releasehub auth login');
128
+ if (status === 404)
129
+ throw new ApiError(`Repository or tag not found. Check --from and --to values.`, 404);
130
+ if (status === 403)
131
+ throw new ApiError('GitHub API rate limit exceeded. Wait a moment and try again.', 403);
132
+ }
133
+ throw err;
134
+ }
135
+ }
136
+ /**
137
+ * Create a GitHub Release for the given tag with the provided body.
138
+ */
139
+ export async function publishGitHubRelease(repo, tag, body) {
140
+ const octokit = getOctokit();
141
+ try {
142
+ const { data } = await octokit.rest.repos.createRelease({
143
+ owner: repo.owner,
144
+ repo: repo.name,
145
+ tag_name: tag,
146
+ name: tag,
147
+ body,
148
+ draft: false,
149
+ prerelease: tag.includes('-'),
150
+ });
151
+ return { id: data.id, html_url: data.html_url, name: data.name ?? tag };
152
+ }
153
+ catch (err) {
154
+ if (err && typeof err === 'object' && 'status' in err) {
155
+ const status = err.status;
156
+ if (status === 401)
157
+ throw new AuthError('GitHub token is invalid or expired. Run: releasehub auth login');
158
+ if (status === 422)
159
+ throw new ApiError(`A release for tag "${tag}" already exists.`, 422);
160
+ if (status === 403)
161
+ throw new ApiError('GitHub API rate limit exceeded. Wait a moment and try again.', 403);
162
+ }
163
+ throw err;
164
+ }
165
+ }
166
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/lib/github.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@releasehub/cli",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered release notes from your terminal",
5
+ "type": "module",
6
+ "bin": {
7
+ "releasehub": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js"
16
+ },
17
+ "dependencies": {
18
+ "@anthropic-ai/sdk": "^0.24.0",
19
+ "@octokit/rest": "^21.0.0",
20
+ "chalk": "^5.3.0",
21
+ "commander": "^12.1.0",
22
+ "openai": "^6.41.0",
23
+ "ora": "^8.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.0.0",
27
+ "typescript": "^5.4.0"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "keywords": [
33
+ "release-notes",
34
+ "changelog",
35
+ "cli",
36
+ "ai",
37
+ "github"
38
+ ],
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/berat/releasehub"
43
+ }
44
+ }