@snapcommit/cli 3.0.1 ā 3.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/dist/commands/cursor-style.js +161 -5
- package/dist/lib/github.js +145 -0
- package/package.json +1 -1
|
@@ -272,9 +272,10 @@ async function executeGitHubCommand(intent) {
|
|
|
272
272
|
try {
|
|
273
273
|
switch (intent.action) {
|
|
274
274
|
case 'pr_create':
|
|
275
|
-
|
|
275
|
+
const isDraft = intent.options?.draft || false;
|
|
276
|
+
console.log(chalk_1.default.blue(`\nš Creating ${isDraft ? 'draft ' : ''}PR...`));
|
|
276
277
|
const pr = await github.createPullRequest(intent.options || {});
|
|
277
|
-
console.log(chalk_1.default.green(`ā PR #${pr.number} created`));
|
|
278
|
+
console.log(chalk_1.default.green(`ā ${isDraft ? 'Draft ' : ''}PR #${pr.number} created`));
|
|
278
279
|
console.log(chalk_1.default.cyan(` ${pr.html_url}\n`));
|
|
279
280
|
break;
|
|
280
281
|
case 'pr_list':
|
|
@@ -291,10 +292,14 @@ async function executeGitHubCommand(intent) {
|
|
|
291
292
|
}
|
|
292
293
|
break;
|
|
293
294
|
case 'pr_merge':
|
|
294
|
-
|
|
295
|
+
let prNumber = intent.target || intent.options?.number;
|
|
296
|
+
// Smart PR detection: "merge my PR" / "merge this PR"
|
|
295
297
|
if (!prNumber) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
+
prNumber = await github.findPRNumber('current');
|
|
299
|
+
if (!prNumber) {
|
|
300
|
+
console.log(chalk_1.default.red('\nā No PR found for current branch\n'));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
298
303
|
}
|
|
299
304
|
console.log(chalk_1.default.blue(`\nš Merging PR #${prNumber}...`));
|
|
300
305
|
await github.mergePullRequest(prNumber);
|
|
@@ -340,6 +345,157 @@ async function executeGitHubCommand(intent) {
|
|
|
340
345
|
console.log();
|
|
341
346
|
}
|
|
342
347
|
break;
|
|
348
|
+
case 'issue_close':
|
|
349
|
+
const closeIssueNum = intent.target || intent.options?.number;
|
|
350
|
+
if (!closeIssueNum) {
|
|
351
|
+
console.log(chalk_1.default.red('\nā Issue number required\n'));
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
console.log(chalk_1.default.blue(`\nš Closing issue #${closeIssueNum}...`));
|
|
355
|
+
await github.closeIssue(closeIssueNum);
|
|
356
|
+
console.log(chalk_1.default.green(`ā Issue #${closeIssueNum} closed\n`));
|
|
357
|
+
break;
|
|
358
|
+
case 'issue_reopen':
|
|
359
|
+
const reopenIssueNum = intent.target || intent.options?.number;
|
|
360
|
+
if (!reopenIssueNum) {
|
|
361
|
+
console.log(chalk_1.default.red('\nā Issue number required\n'));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
console.log(chalk_1.default.blue(`\nš Reopening issue #${reopenIssueNum}...`));
|
|
365
|
+
await github.reopenIssue(reopenIssueNum);
|
|
366
|
+
console.log(chalk_1.default.green(`ā Issue #${reopenIssueNum} reopened\n`));
|
|
367
|
+
break;
|
|
368
|
+
case 'pr_review':
|
|
369
|
+
let reviewPrNum = intent.target || intent.options?.number;
|
|
370
|
+
// Smart PR detection: "approve this PR" / "approve my PR"
|
|
371
|
+
if (!reviewPrNum) {
|
|
372
|
+
const context = intent.options?.context || 'current';
|
|
373
|
+
reviewPrNum = await github.findPRNumber(context);
|
|
374
|
+
if (!reviewPrNum) {
|
|
375
|
+
console.log(chalk_1.default.red('\nā No PR found for current branch'));
|
|
376
|
+
console.log(chalk_1.default.gray(' Try: "approve PR #123" or create a PR first\n'));
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const reviewType = intent.options?.type || 'APPROVE';
|
|
381
|
+
const reviewBody = intent.options?.body || '';
|
|
382
|
+
console.log(chalk_1.default.blue(`\nš Reviewing PR #${reviewPrNum}...`));
|
|
383
|
+
await github.reviewPullRequest(reviewPrNum, {
|
|
384
|
+
event: reviewType,
|
|
385
|
+
body: reviewBody,
|
|
386
|
+
});
|
|
387
|
+
if (reviewType === 'APPROVE') {
|
|
388
|
+
console.log(chalk_1.default.green(`ā Approved PR #${reviewPrNum}\n`));
|
|
389
|
+
}
|
|
390
|
+
else if (reviewType === 'REQUEST_CHANGES') {
|
|
391
|
+
console.log(chalk_1.default.yellow(`ā ļø Requested changes on PR #${reviewPrNum}\n`));
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
console.log(chalk_1.default.green(`ā Commented on PR #${reviewPrNum}\n`));
|
|
395
|
+
}
|
|
396
|
+
break;
|
|
397
|
+
case 'pr_comment':
|
|
398
|
+
let commentPrNum = intent.target || intent.options?.number;
|
|
399
|
+
// Smart PR detection
|
|
400
|
+
if (!commentPrNum) {
|
|
401
|
+
commentPrNum = await github.findPRNumber('current');
|
|
402
|
+
if (!commentPrNum) {
|
|
403
|
+
console.log(chalk_1.default.red('\nā No PR found for current branch\n'));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const prComment = intent.options?.body || intent.options?.comment || '';
|
|
408
|
+
if (!prComment) {
|
|
409
|
+
console.log(chalk_1.default.red('\nā Comment text required\n'));
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
console.log(chalk_1.default.blue(`\nš¬ Commenting on PR #${commentPrNum}...`));
|
|
413
|
+
await github.commentOnPullRequest(commentPrNum, prComment);
|
|
414
|
+
console.log(chalk_1.default.green(`ā Comment added\n`));
|
|
415
|
+
break;
|
|
416
|
+
case 'issue_comment':
|
|
417
|
+
const commentIssueNum = intent.target || intent.options?.number;
|
|
418
|
+
if (!commentIssueNum) {
|
|
419
|
+
console.log(chalk_1.default.red('\nā Issue number required\n'));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const issueComment = intent.options?.body || intent.options?.comment || '';
|
|
423
|
+
if (!issueComment) {
|
|
424
|
+
console.log(chalk_1.default.red('\nā Comment text required\n'));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
console.log(chalk_1.default.blue(`\nš¬ Commenting on issue #${commentIssueNum}...`));
|
|
428
|
+
await github.commentOnIssue(commentIssueNum, issueComment);
|
|
429
|
+
console.log(chalk_1.default.green(`ā Comment added\n`));
|
|
430
|
+
break;
|
|
431
|
+
case 'pr_show':
|
|
432
|
+
case 'pr_status':
|
|
433
|
+
let showPrNum = intent.target || intent.options?.number;
|
|
434
|
+
// Smart PR detection: "show my PR" / "show this PR"
|
|
435
|
+
if (!showPrNum) {
|
|
436
|
+
showPrNum = await github.findPRNumber('current');
|
|
437
|
+
if (!showPrNum) {
|
|
438
|
+
console.log(chalk_1.default.red('\nā No PR found for current branch\n'));
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
console.log(chalk_1.default.blue(`\nš PR #${showPrNum}:\n`));
|
|
443
|
+
const prDetails = await github.getPullRequest(showPrNum);
|
|
444
|
+
console.log(chalk_1.default.white.bold(` ${prDetails.title}`));
|
|
445
|
+
console.log(chalk_1.default.gray(` ${prDetails.user.login} wants to merge ${chalk_1.default.cyan(prDetails.head.ref)} ā ${chalk_1.default.cyan(prDetails.base.ref)}`));
|
|
446
|
+
console.log();
|
|
447
|
+
if (prDetails.state === 'open') {
|
|
448
|
+
console.log(chalk_1.default.green(' ā Open'));
|
|
449
|
+
}
|
|
450
|
+
else if (prDetails.merged) {
|
|
451
|
+
console.log(chalk_1.default.magenta(' ā Merged'));
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
console.log(chalk_1.default.red(' ā Closed'));
|
|
455
|
+
}
|
|
456
|
+
console.log(chalk_1.default.gray(` ${prDetails.comments} comments ⢠${prDetails.commits} commits ⢠${prDetails.changed_files} files\n`));
|
|
457
|
+
if (prDetails.body) {
|
|
458
|
+
console.log(chalk_1.default.white(' Description:'));
|
|
459
|
+
console.log(chalk_1.default.gray(` ${prDetails.body.substring(0, 200)}${prDetails.body.length > 200 ? '...' : ''}\n`));
|
|
460
|
+
}
|
|
461
|
+
break;
|
|
462
|
+
case 'pr_diff':
|
|
463
|
+
let diffPrNum = intent.target || intent.options?.number;
|
|
464
|
+
// Smart PR detection: "what changed in my PR"
|
|
465
|
+
if (!diffPrNum) {
|
|
466
|
+
diffPrNum = await github.findPRNumber('current');
|
|
467
|
+
if (!diffPrNum) {
|
|
468
|
+
console.log(chalk_1.default.red('\nā No PR found for current branch\n'));
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
console.log(chalk_1.default.blue(`\nš PR #${diffPrNum} changes:\n`));
|
|
473
|
+
const files = await github.getPullRequestFiles(diffPrNum);
|
|
474
|
+
files.forEach((file) => {
|
|
475
|
+
let symbol = 'ā';
|
|
476
|
+
let color = chalk_1.default.yellow;
|
|
477
|
+
if (file.status === 'added') {
|
|
478
|
+
symbol = '+';
|
|
479
|
+
color = chalk_1.default.green;
|
|
480
|
+
}
|
|
481
|
+
else if (file.status === 'removed') {
|
|
482
|
+
symbol = '-';
|
|
483
|
+
color = chalk_1.default.red;
|
|
484
|
+
}
|
|
485
|
+
console.log(color(` ${symbol} ${file.filename}`) + chalk_1.default.gray(` (+${file.additions} -${file.deletions})`));
|
|
486
|
+
});
|
|
487
|
+
console.log();
|
|
488
|
+
break;
|
|
489
|
+
case 'workflow_rerun':
|
|
490
|
+
const runId = intent.target || intent.options?.runId;
|
|
491
|
+
if (!runId) {
|
|
492
|
+
console.log(chalk_1.default.red('\nā Workflow run ID required\n'));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
console.log(chalk_1.default.blue(`\nš Re-running workflow #${runId}...`));
|
|
496
|
+
await github.rerunWorkflow(runId);
|
|
497
|
+
console.log(chalk_1.default.green(`ā Workflow re-run started\n`));
|
|
498
|
+
break;
|
|
343
499
|
default:
|
|
344
500
|
console.log(chalk_1.default.yellow(`\nā ļø Action not supported: ${intent.action}\n`));
|
|
345
501
|
}
|
package/dist/lib/github.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCurrentRepo = getCurrentRepo;
|
|
4
4
|
exports.getCurrentBranch = getCurrentBranch;
|
|
5
|
+
exports.findPRNumber = findPRNumber;
|
|
6
|
+
exports.findIssueNumber = findIssueNumber;
|
|
5
7
|
exports.createPullRequest = createPullRequest;
|
|
6
8
|
exports.listPullRequests = listPullRequests;
|
|
7
9
|
exports.getPullRequest = getPullRequest;
|
|
@@ -14,6 +16,13 @@ exports.listIssues = listIssues;
|
|
|
14
16
|
exports.closeIssue = closeIssue;
|
|
15
17
|
exports.createRelease = createRelease;
|
|
16
18
|
exports.getRepoInfo = getRepoInfo;
|
|
19
|
+
exports.reviewPullRequest = reviewPullRequest;
|
|
20
|
+
exports.commentOnPullRequest = commentOnPullRequest;
|
|
21
|
+
exports.commentOnIssue = commentOnIssue;
|
|
22
|
+
exports.getPullRequestDiff = getPullRequestDiff;
|
|
23
|
+
exports.reopenIssue = reopenIssue;
|
|
24
|
+
exports.rerunWorkflow = rerunWorkflow;
|
|
25
|
+
exports.getPullRequestFiles = getPullRequestFiles;
|
|
17
26
|
const child_process_1 = require("child_process");
|
|
18
27
|
const github_connect_1 = require("../commands/github-connect");
|
|
19
28
|
const GITHUB_API = 'https://api.github.com';
|
|
@@ -56,6 +65,41 @@ function getCurrentBranch() {
|
|
|
56
65
|
return 'main';
|
|
57
66
|
}
|
|
58
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Find PR number from context (current branch, latest, etc.)
|
|
70
|
+
*/
|
|
71
|
+
async function findPRNumber(context) {
|
|
72
|
+
try {
|
|
73
|
+
if (context === 'current' || !context) {
|
|
74
|
+
// Find PR for current branch
|
|
75
|
+
const branch = getCurrentBranch();
|
|
76
|
+
const prs = await listPullRequests({ state: 'open', limit: 50 });
|
|
77
|
+
const pr = prs.find((p) => p.head.ref === branch);
|
|
78
|
+
return pr ? pr.number : null;
|
|
79
|
+
}
|
|
80
|
+
else if (context === 'latest' || context === 'mine') {
|
|
81
|
+
// Get latest PR
|
|
82
|
+
const prs = await listPullRequests({ state: 'open', limit: 1 });
|
|
83
|
+
return prs.length > 0 ? prs[0].number : null;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Find issue number from context (latest, etc.)
|
|
93
|
+
*/
|
|
94
|
+
async function findIssueNumber(context) {
|
|
95
|
+
try {
|
|
96
|
+
const issues = await listIssues({ state: 'open', limit: 1 });
|
|
97
|
+
return issues.length > 0 ? issues[0].number : null;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
59
103
|
/**
|
|
60
104
|
* GitHub API request helper - uses locally stored token
|
|
61
105
|
*/
|
|
@@ -109,6 +153,7 @@ async function createPullRequest(options) {
|
|
|
109
153
|
body,
|
|
110
154
|
head: currentBranch,
|
|
111
155
|
base: baseBranch,
|
|
156
|
+
draft: options.draft || false,
|
|
112
157
|
}),
|
|
113
158
|
});
|
|
114
159
|
return pr;
|
|
@@ -272,3 +317,103 @@ async function getRepoInfo() {
|
|
|
272
317
|
}
|
|
273
318
|
return await githubRequest(`/repos/${repo.owner}/${repo.name}`);
|
|
274
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Review a Pull Request
|
|
322
|
+
*/
|
|
323
|
+
async function reviewPullRequest(prNumber, options) {
|
|
324
|
+
const repo = getCurrentRepo();
|
|
325
|
+
if (!repo) {
|
|
326
|
+
throw new Error('Not a GitHub repository');
|
|
327
|
+
}
|
|
328
|
+
return await githubRequest(`/repos/${repo.owner}/${repo.name}/pulls/${prNumber}/reviews`, {
|
|
329
|
+
method: 'POST',
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
event: options.event,
|
|
332
|
+
body: options.body || '',
|
|
333
|
+
}),
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Comment on a Pull Request
|
|
338
|
+
*/
|
|
339
|
+
async function commentOnPullRequest(prNumber, body) {
|
|
340
|
+
const repo = getCurrentRepo();
|
|
341
|
+
if (!repo) {
|
|
342
|
+
throw new Error('Not a GitHub repository');
|
|
343
|
+
}
|
|
344
|
+
return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${prNumber}/comments`, {
|
|
345
|
+
method: 'POST',
|
|
346
|
+
body: JSON.stringify({ body }),
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Comment on an Issue
|
|
351
|
+
*/
|
|
352
|
+
async function commentOnIssue(issueNumber, body) {
|
|
353
|
+
const repo = getCurrentRepo();
|
|
354
|
+
if (!repo) {
|
|
355
|
+
throw new Error('Not a GitHub repository');
|
|
356
|
+
}
|
|
357
|
+
return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${issueNumber}/comments`, {
|
|
358
|
+
method: 'POST',
|
|
359
|
+
body: JSON.stringify({ body }),
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Get PR diff
|
|
364
|
+
*/
|
|
365
|
+
async function getPullRequestDiff(prNumber) {
|
|
366
|
+
const repo = getCurrentRepo();
|
|
367
|
+
if (!repo) {
|
|
368
|
+
throw new Error('Not a GitHub repository');
|
|
369
|
+
}
|
|
370
|
+
const token = (0, github_connect_1.getGitHubToken)();
|
|
371
|
+
if (!token) {
|
|
372
|
+
throw new Error('GitHub not connected. Run: snap github connect');
|
|
373
|
+
}
|
|
374
|
+
const response = await fetch(`${GITHUB_API}/repos/${repo.owner}/${repo.name}/pulls/${prNumber}`, {
|
|
375
|
+
headers: {
|
|
376
|
+
Authorization: `Bearer ${token}`,
|
|
377
|
+
Accept: 'application/vnd.github.diff',
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
if (!response.ok) {
|
|
381
|
+
throw new Error('Failed to fetch PR diff');
|
|
382
|
+
}
|
|
383
|
+
return await response.text();
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Reopen an issue
|
|
387
|
+
*/
|
|
388
|
+
async function reopenIssue(issueNumber) {
|
|
389
|
+
const repo = getCurrentRepo();
|
|
390
|
+
if (!repo) {
|
|
391
|
+
throw new Error('Not a GitHub repository');
|
|
392
|
+
}
|
|
393
|
+
return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${issueNumber}`, {
|
|
394
|
+
method: 'PATCH',
|
|
395
|
+
body: JSON.stringify({ state: 'open' }),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Re-run workflow
|
|
400
|
+
*/
|
|
401
|
+
async function rerunWorkflow(runId) {
|
|
402
|
+
const repo = getCurrentRepo();
|
|
403
|
+
if (!repo) {
|
|
404
|
+
throw new Error('Not a GitHub repository');
|
|
405
|
+
}
|
|
406
|
+
await githubRequest(`/repos/${repo.owner}/${repo.name}/actions/runs/${runId}/rerun`, {
|
|
407
|
+
method: 'POST',
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get PR files (what changed)
|
|
412
|
+
*/
|
|
413
|
+
async function getPullRequestFiles(prNumber) {
|
|
414
|
+
const repo = getCurrentRepo();
|
|
415
|
+
if (!repo) {
|
|
416
|
+
throw new Error('Not a GitHub repository');
|
|
417
|
+
}
|
|
418
|
+
return await githubRequest(`/repos/${repo.owner}/${repo.name}/pulls/${prNumber}/files`);
|
|
419
|
+
}
|