@snapcommit/cli 3.0.1 → 3.1.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.
@@ -272,9 +272,10 @@ async function executeGitHubCommand(intent) {
272
272
  try {
273
273
  switch (intent.action) {
274
274
  case 'pr_create':
275
- console.log(chalk_1.default.blue('\nšŸ”„ Creating PR...'));
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':
@@ -340,6 +341,139 @@ async function executeGitHubCommand(intent) {
340
341
  console.log();
341
342
  }
342
343
  break;
344
+ case 'issue_close':
345
+ const closeIssueNum = intent.target || intent.options?.number;
346
+ if (!closeIssueNum) {
347
+ console.log(chalk_1.default.red('\nāŒ Issue number required\n'));
348
+ return;
349
+ }
350
+ console.log(chalk_1.default.blue(`\nšŸ”„ Closing issue #${closeIssueNum}...`));
351
+ await github.closeIssue(closeIssueNum);
352
+ console.log(chalk_1.default.green(`āœ“ Issue #${closeIssueNum} closed\n`));
353
+ break;
354
+ case 'issue_reopen':
355
+ const reopenIssueNum = intent.target || intent.options?.number;
356
+ if (!reopenIssueNum) {
357
+ console.log(chalk_1.default.red('\nāŒ Issue number required\n'));
358
+ return;
359
+ }
360
+ console.log(chalk_1.default.blue(`\nšŸ”„ Reopening issue #${reopenIssueNum}...`));
361
+ await github.reopenIssue(reopenIssueNum);
362
+ console.log(chalk_1.default.green(`āœ“ Issue #${reopenIssueNum} reopened\n`));
363
+ break;
364
+ case 'pr_review':
365
+ const reviewPrNum = intent.target || intent.options?.number;
366
+ if (!reviewPrNum) {
367
+ console.log(chalk_1.default.red('\nāŒ PR number required\n'));
368
+ return;
369
+ }
370
+ const reviewType = intent.options?.type || 'APPROVE';
371
+ const reviewBody = intent.options?.body || '';
372
+ console.log(chalk_1.default.blue(`\nšŸ”„ Reviewing PR #${reviewPrNum}...`));
373
+ await github.reviewPullRequest(reviewPrNum, {
374
+ event: reviewType,
375
+ body: reviewBody,
376
+ });
377
+ if (reviewType === 'APPROVE') {
378
+ console.log(chalk_1.default.green(`āœ“ Approved PR #${reviewPrNum}\n`));
379
+ }
380
+ else if (reviewType === 'REQUEST_CHANGES') {
381
+ console.log(chalk_1.default.yellow(`āš ļø Requested changes on PR #${reviewPrNum}\n`));
382
+ }
383
+ else {
384
+ console.log(chalk_1.default.green(`āœ“ Commented on PR #${reviewPrNum}\n`));
385
+ }
386
+ break;
387
+ case 'pr_comment':
388
+ const commentPrNum = intent.target || intent.options?.number;
389
+ if (!commentPrNum) {
390
+ console.log(chalk_1.default.red('\nāŒ PR number required\n'));
391
+ return;
392
+ }
393
+ const prComment = intent.options?.body || intent.options?.comment || '';
394
+ if (!prComment) {
395
+ console.log(chalk_1.default.red('\nāŒ Comment text required\n'));
396
+ return;
397
+ }
398
+ console.log(chalk_1.default.blue(`\nšŸ’¬ Commenting on PR #${commentPrNum}...`));
399
+ await github.commentOnPullRequest(commentPrNum, prComment);
400
+ console.log(chalk_1.default.green(`āœ“ Comment added\n`));
401
+ break;
402
+ case 'issue_comment':
403
+ const commentIssueNum = intent.target || intent.options?.number;
404
+ if (!commentIssueNum) {
405
+ console.log(chalk_1.default.red('\nāŒ Issue number required\n'));
406
+ return;
407
+ }
408
+ const issueComment = intent.options?.body || intent.options?.comment || '';
409
+ if (!issueComment) {
410
+ console.log(chalk_1.default.red('\nāŒ Comment text required\n'));
411
+ return;
412
+ }
413
+ console.log(chalk_1.default.blue(`\nšŸ’¬ Commenting on issue #${commentIssueNum}...`));
414
+ await github.commentOnIssue(commentIssueNum, issueComment);
415
+ console.log(chalk_1.default.green(`āœ“ Comment added\n`));
416
+ break;
417
+ case 'pr_show':
418
+ case 'pr_status':
419
+ const showPrNum = intent.target || intent.options?.number;
420
+ if (!showPrNum) {
421
+ console.log(chalk_1.default.red('\nāŒ PR number required\n'));
422
+ return;
423
+ }
424
+ console.log(chalk_1.default.blue(`\nšŸ“‹ PR #${showPrNum}:\n`));
425
+ const prDetails = await github.getPullRequest(showPrNum);
426
+ console.log(chalk_1.default.white.bold(` ${prDetails.title}`));
427
+ 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)}`));
428
+ console.log();
429
+ if (prDetails.state === 'open') {
430
+ console.log(chalk_1.default.green(' āœ“ Open'));
431
+ }
432
+ else if (prDetails.merged) {
433
+ console.log(chalk_1.default.magenta(' āœ“ Merged'));
434
+ }
435
+ else {
436
+ console.log(chalk_1.default.red(' āœ— Closed'));
437
+ }
438
+ console.log(chalk_1.default.gray(` ${prDetails.comments} comments • ${prDetails.commits} commits • ${prDetails.changed_files} files\n`));
439
+ if (prDetails.body) {
440
+ console.log(chalk_1.default.white(' Description:'));
441
+ console.log(chalk_1.default.gray(` ${prDetails.body.substring(0, 200)}${prDetails.body.length > 200 ? '...' : ''}\n`));
442
+ }
443
+ break;
444
+ case 'pr_diff':
445
+ const diffPrNum = intent.target || intent.options?.number;
446
+ if (!diffPrNum) {
447
+ console.log(chalk_1.default.red('\nāŒ PR number required\n'));
448
+ return;
449
+ }
450
+ console.log(chalk_1.default.blue(`\nšŸ“„ PR #${diffPrNum} changes:\n`));
451
+ const files = await github.getPullRequestFiles(diffPrNum);
452
+ files.forEach((file) => {
453
+ let symbol = 'āœŽ';
454
+ let color = chalk_1.default.yellow;
455
+ if (file.status === 'added') {
456
+ symbol = '+';
457
+ color = chalk_1.default.green;
458
+ }
459
+ else if (file.status === 'removed') {
460
+ symbol = '-';
461
+ color = chalk_1.default.red;
462
+ }
463
+ console.log(color(` ${symbol} ${file.filename}`) + chalk_1.default.gray(` (+${file.additions} -${file.deletions})`));
464
+ });
465
+ console.log();
466
+ break;
467
+ case 'workflow_rerun':
468
+ const runId = intent.target || intent.options?.runId;
469
+ if (!runId) {
470
+ console.log(chalk_1.default.red('\nāŒ Workflow run ID required\n'));
471
+ return;
472
+ }
473
+ console.log(chalk_1.default.blue(`\nšŸ”„ Re-running workflow #${runId}...`));
474
+ await github.rerunWorkflow(runId);
475
+ console.log(chalk_1.default.green(`āœ“ Workflow re-run started\n`));
476
+ break;
343
477
  default:
344
478
  console.log(chalk_1.default.yellow(`\nāš ļø Action not supported: ${intent.action}\n`));
345
479
  }
@@ -14,6 +14,13 @@ exports.listIssues = listIssues;
14
14
  exports.closeIssue = closeIssue;
15
15
  exports.createRelease = createRelease;
16
16
  exports.getRepoInfo = getRepoInfo;
17
+ exports.reviewPullRequest = reviewPullRequest;
18
+ exports.commentOnPullRequest = commentOnPullRequest;
19
+ exports.commentOnIssue = commentOnIssue;
20
+ exports.getPullRequestDiff = getPullRequestDiff;
21
+ exports.reopenIssue = reopenIssue;
22
+ exports.rerunWorkflow = rerunWorkflow;
23
+ exports.getPullRequestFiles = getPullRequestFiles;
17
24
  const child_process_1 = require("child_process");
18
25
  const github_connect_1 = require("../commands/github-connect");
19
26
  const GITHUB_API = 'https://api.github.com';
@@ -109,6 +116,7 @@ async function createPullRequest(options) {
109
116
  body,
110
117
  head: currentBranch,
111
118
  base: baseBranch,
119
+ draft: options.draft || false,
112
120
  }),
113
121
  });
114
122
  return pr;
@@ -272,3 +280,103 @@ async function getRepoInfo() {
272
280
  }
273
281
  return await githubRequest(`/repos/${repo.owner}/${repo.name}`);
274
282
  }
283
+ /**
284
+ * Review a Pull Request
285
+ */
286
+ async function reviewPullRequest(prNumber, options) {
287
+ const repo = getCurrentRepo();
288
+ if (!repo) {
289
+ throw new Error('Not a GitHub repository');
290
+ }
291
+ return await githubRequest(`/repos/${repo.owner}/${repo.name}/pulls/${prNumber}/reviews`, {
292
+ method: 'POST',
293
+ body: JSON.stringify({
294
+ event: options.event,
295
+ body: options.body || '',
296
+ }),
297
+ });
298
+ }
299
+ /**
300
+ * Comment on a Pull Request
301
+ */
302
+ async function commentOnPullRequest(prNumber, body) {
303
+ const repo = getCurrentRepo();
304
+ if (!repo) {
305
+ throw new Error('Not a GitHub repository');
306
+ }
307
+ return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${prNumber}/comments`, {
308
+ method: 'POST',
309
+ body: JSON.stringify({ body }),
310
+ });
311
+ }
312
+ /**
313
+ * Comment on an Issue
314
+ */
315
+ async function commentOnIssue(issueNumber, body) {
316
+ const repo = getCurrentRepo();
317
+ if (!repo) {
318
+ throw new Error('Not a GitHub repository');
319
+ }
320
+ return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${issueNumber}/comments`, {
321
+ method: 'POST',
322
+ body: JSON.stringify({ body }),
323
+ });
324
+ }
325
+ /**
326
+ * Get PR diff
327
+ */
328
+ async function getPullRequestDiff(prNumber) {
329
+ const repo = getCurrentRepo();
330
+ if (!repo) {
331
+ throw new Error('Not a GitHub repository');
332
+ }
333
+ const token = (0, github_connect_1.getGitHubToken)();
334
+ if (!token) {
335
+ throw new Error('GitHub not connected. Run: snap github connect');
336
+ }
337
+ const response = await fetch(`${GITHUB_API}/repos/${repo.owner}/${repo.name}/pulls/${prNumber}`, {
338
+ headers: {
339
+ Authorization: `Bearer ${token}`,
340
+ Accept: 'application/vnd.github.diff',
341
+ },
342
+ });
343
+ if (!response.ok) {
344
+ throw new Error('Failed to fetch PR diff');
345
+ }
346
+ return await response.text();
347
+ }
348
+ /**
349
+ * Reopen an issue
350
+ */
351
+ async function reopenIssue(issueNumber) {
352
+ const repo = getCurrentRepo();
353
+ if (!repo) {
354
+ throw new Error('Not a GitHub repository');
355
+ }
356
+ return await githubRequest(`/repos/${repo.owner}/${repo.name}/issues/${issueNumber}`, {
357
+ method: 'PATCH',
358
+ body: JSON.stringify({ state: 'open' }),
359
+ });
360
+ }
361
+ /**
362
+ * Re-run workflow
363
+ */
364
+ async function rerunWorkflow(runId) {
365
+ const repo = getCurrentRepo();
366
+ if (!repo) {
367
+ throw new Error('Not a GitHub repository');
368
+ }
369
+ await githubRequest(`/repos/${repo.owner}/${repo.name}/actions/runs/${runId}/rerun`, {
370
+ method: 'POST',
371
+ });
372
+ }
373
+ /**
374
+ * Get PR files (what changed)
375
+ */
376
+ async function getPullRequestFiles(prNumber) {
377
+ const repo = getCurrentRepo();
378
+ if (!repo) {
379
+ throw new Error('Not a GitHub repository');
380
+ }
381
+ return await githubRequest(`/repos/${repo.owner}/${repo.name}/pulls/${prNumber}/files`);
382
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snapcommit/cli",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Instant AI commits. Beautiful progress tracking. Never write commit messages again.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {