prsmith 1.0.1 → 1.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.1.0] - 2026-06-01
6
+
7
+ ### Added
8
+ - **Clipboard Integration**: Automatically copies the generated markdown to your clipboard (`clipboardy`).
9
+ - **Editor Prompts**: The `issue` and `fix` interactive prompts now intelligently launch your default system `$EDITOR` (e.g. VS Code, vim) for a seamless multi-line typing experience.
10
+ - **CLI Arguments**: You can completely bypass the interactive mode by supplying flags: `-s`, `-t`, `-i`, `-f`.
11
+ - **File Output**: Use the `-o` or `--out` flag to directly write the markdown to a file (e.g. `prsmith --out comment.md`).
12
+ - **Update Notifier**: The CLI now checks for updates in the background and notifies you if a newer version is available on NPM.
13
+ - **Custom Configs**: Support for `.prsmith.json` files in your home directory (`~/`) or project directory. Define your own custom severities and intro templates!
14
+
15
+ ## [1.0.2] - 2026-05-31
16
+
17
+ ### Added
18
+ - Integrated `commander` to provide robust native support for CLI flags (`-h`, `--help`, `-v`, `--version`).
19
+ - Graceful termination handling: Intercepting `ExitPromptError` to display a friendly message when users abort the interactive prompt (e.g., via `Ctrl+C`) instead of throwing stack traces.
20
+ - Custom author branding and detailed bio added to the README footer.
21
+
22
+ ## [1.0.1] - 2026-05-31
23
+
24
+ ### Fixed
25
+ - Re-configured Git Hooks (Husky) to ensure `npm test` and `npm run lint` run reliably on pre-commit.
26
+ - Resolved invalid path structures in `package.json` for the executable `bin` field.
27
+ - Fixed a bug in `inquirer` by migrating legacy `"list"` prompt types to `"select"` to prevent CLI crashes.
28
+
29
+ ### Changed
30
+ - Massively overhauled `README.md` for NPM compatibility: Replaced unsupported Mermaid diagrams with elegant ASCII flowcharts, incorporated GitHub/NPM badges, and structured sections with collapsible `<details>` HTML tags for premium rendering on the NPM website.
31
+
5
32
  ## [1.0.0] - 2026-05-31
6
33
 
7
34
  ### Added
package/README.md CHANGED
@@ -1,28 +1,38 @@
1
- # PRSmith
1
+ <div align="center">
2
+ <h1>PRSmith</h1>
3
+
4
+ [![npm version](https://img.shields.io/npm/v/prsmith.svg?style=flat-square)](https://www.npmjs.com/package/prsmith)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/TarunyaProgrammer/PRSmith_NPMPackage/ci.yml?branch=main&style=flat-square)](https://github.com/TarunyaProgrammer/PRSmith_NPMPackage/actions)
2
7
 
3
- [![npm version](https://img.shields.io/npm/v/prsmith.svg?style=flat-square)](https://www.npmjs.com/package/prsmith)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
- [![CI](https://img.shields.io/github/actions/workflow/status/TarunyaProgrammer/PRSmith_NPMPackage/ci.yml?branch=main&style=flat-square)](https://github.com/TarunyaProgrammer/PRSmith_NPMPackage/actions)
8
+ <p><b>Forge professional pull request review comments directly from the terminal.</b></p>
9
+ </div>
6
10
 
7
- Forge professional pull request review comments directly from the terminal.
11
+ ---
8
12
 
9
13
  PRSmith streamlines the process of writing code reviews by providing an interactive prompt that generates consistently formatted, polite, and actionable Markdown comments.
10
14
 
11
- ---
12
-
13
15
  ## Architecture Flow
14
16
 
15
17
  The tool operates via a straightforward interactive flow, generating structured markdown from your inputs.
16
18
 
17
- ```mermaid
18
- graph TD
19
- A[User runs 'prsmith'] --> B{Interactive Prompts}
20
- B -->|Severity| C[Select Critical, Major, Minor, Suggestion]
21
- B -->|Title| D[Enter Title]
22
- B -->|Issue| E[Describe Problem]
23
- B -->|Fix| F[Suggest Fix]
24
- C & D & E & F --> G[Markdown Generator]
25
- G --> H[Print Formatted PR Comment]
19
+ ```text
20
+ ┌──────────────────────────┐
21
+ │ Run `prsmith` Command │
22
+ └────────────┬─────────────┘
23
+
24
+ ┌──────────────────────────┐
25
+ │ Interactive Prompts │
26
+ (Severity, Title, Issue)
27
+ └────────────┬─────────────┘
28
+
29
+ ┌──────────────────────────┐
30
+ │ Markdown Generation │
31
+ └────────────┬─────────────┘
32
+
33
+ ┌──────────────────────────┐
34
+ │ Print Formatted Comment │
35
+ └──────────────────────────┘
26
36
  ```
27
37
 
28
38
  ---
@@ -35,25 +45,71 @@ Install globally to use it anywhere on your machine.
35
45
  npm install -g prsmith
36
46
  ```
37
47
 
38
- ## Usage
48
+ ## ✨ Advanced Features (v1.1.0)
39
49
 
40
- Simply run the command in your terminal:
50
+ - **Interactive Editor Prompts:** For multi-line issues, PRSmith temporarily opens your system's default `$EDITOR` (like VS Code or Vim) so you can type formatted text seamlessly.
51
+ - **Auto-Clipboard:** No need to manually highlight terminal output! The generated markdown is automatically copied to your clipboard.
52
+ - **Bypass Prompts:** Skip the interactive flow completely by using CLI arguments (perfect for scripting).
53
+ - **File Output:** Directly write the output to a `.md` file using the `--out` flag.
54
+ - **Custom Templates:** Create a `.prsmith.json` file in your project or home directory to define your own severity levels and custom intro messages.
55
+
56
+ ## 💻 Usage
57
+
58
+ ### Interactive Mode
59
+ The primary way to use PRSmith is via its interactive mode. Simply run:
41
60
 
42
61
  ```bash
43
62
  prsmith
44
63
  ```
64
+ This will launch the interactive prompt. When asked to describe the issue or fix, your default terminal editor will launch, allowing you to write multi-line markdown!
65
+
66
+ ### Non-Interactive Flags
67
+
68
+ You can bypass the prompts entirely:
69
+
70
+ ```bash
71
+ prsmith -s Critical -t "Memory Leak" -i "Connection left open." -f "Add a finally block." -o review.md
72
+ ```
73
+
74
+ | Flag | Full | Description |
75
+ | :--- | :--- | :--- |
76
+ | `-s` | `--severity` | Severity level (e.g., Critical, Minor) |
77
+ | `-t` | `--title` | The review title |
78
+ | `-i` | `--issue` | Description of the problem |
79
+ | `-f` | `--fix` | Suggested solution |
80
+ | `-o` | `--out` | Save generated markdown to a specific file |
81
+
82
+ ### Configuration (`.prsmith.json`)
83
+
84
+ You can define custom templates by creating a `.prsmith.json` in your home directory (`~/`) or current working directory:
85
+
86
+ ```json
87
+ {
88
+ "templates": {
89
+ "Nitpick": "This is just a tiny nitpick, no pressure to fix.",
90
+ "Security": "CRITICAL SECURITY VULNERABILITY DETECTED."
91
+ }
92
+ }
93
+ ```
94
+ If you pass `-s Nitpick` (or select it in the CLI), PRSmith will automatically use your custom text!
95
+
96
+ <details>
97
+ <summary><b>Click to view an Example Interaction</b></summary>
45
98
 
46
- ## Example Interaction
99
+ <br/>
47
100
 
48
- **Input:**
101
+ **Input Data:**
49
102
 
50
- - Severity: `Critical`
51
- - Title: `Scope Issue`
52
- - Issue: `Utility functions are nested incorrectly.`
53
- - Suggested Fix: `Move them to module scope.`
103
+ | Field | Input |
104
+ | :--- | :--- |
105
+ | **Severity** | `<kbd>Critical</kbd>` |
106
+ | **Title** | `Scope Issue` |
107
+ | **Issue** | `Utility functions are nested incorrectly.` |
108
+ | **Suggested Fix** | `Move them to module scope.` |
54
109
 
55
- **Output:**
110
+ **Output Markdown:**
56
111
 
112
+ ```md
57
113
  ### Critical: Scope Issue
58
114
 
59
115
  The current implementation introduces a critical issue.
@@ -65,9 +121,19 @@ Utility functions are nested incorrectly.
65
121
  **Suggested Fix**
66
122
 
67
123
  Move them to module scope.
124
+ ```
125
+
126
+ </details>
127
+
128
+ ---
68
129
 
69
130
  ## Development & Contribution
70
131
 
132
+ <details>
133
+ <summary><b>Local Setup Guide</b></summary>
134
+
135
+ <br/>
136
+
71
137
  To set up the project locally:
72
138
 
73
139
  ```bash
@@ -86,7 +152,27 @@ npm run lint
86
152
  # Format the code
87
153
  npm run format
88
154
  ```
155
+ </details>
89
156
 
90
157
  ## License
91
158
 
92
159
  This project is licensed under the MIT License.
160
+
161
+ ---
162
+
163
+ <div align="center">
164
+ <h3>Built with 💻 by Tarunya Kesharwani</h3>
165
+
166
+ <p>
167
+ <i>"I build things. Usually web apps, sometimes automation scripts that save me from doing something tedious twice."</i>
168
+ </p>
169
+
170
+ <p>
171
+ I'm a Full-Stack Engineer and Open Source fanatic (GSoC'26 @ C2SI, Mentor @ GSSoC & SSoC). I obsess over frontend architecture that doesn't collapse under its own weight, seamless developer experiences, and building UI that feels intentional. When I'm not writing TypeScript, I'm probably deep in a rabbit hole about AI, startup strategy, or restructuring a folder hierarchy for the third time.
172
+ </p>
173
+
174
+ <p>
175
+ <a href="https://www.github.com/tarunyaprogrammer"><b>GitHub</b></a> &nbsp;&bull;&nbsp;
176
+ <a href="https://www.linkedin.com/in/tarunyakesharwani/"><b>LinkedIn</b></a>
177
+ </p>
178
+ </div>
package/bin/cli.js CHANGED
@@ -1,30 +1,64 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
3
6
  import chalk from "chalk";
7
+ import { program } from "commander";
8
+ import clipboardy from "clipboardy";
9
+ import updateNotifier from "update-notifier";
4
10
  import { getReviewData } from "../src/prompts.js";
5
11
  import { generateMarkdown } from "../src/formatter.js";
12
+ import { loadConfig } from "../src/config.js";
6
13
 
7
- async function main() {
8
- try {
9
- console.log(
10
- chalk.cyan("\nPRSmith - Professional PR Review Comment Generator\n")
11
- );
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ const pkg = JSON.parse(
17
+ fs.readFileSync(path.join(__dirname, "../package.json"), "utf8")
18
+ );
12
19
 
13
- const data = await getReviewData();
20
+ updateNotifier({ pkg }).notify();
14
21
 
15
- const markdown = generateMarkdown(data);
22
+ program
23
+ .name("prsmith")
24
+ .description("Forge professional pull request review comments directly from the terminal.")
25
+ .version(pkg.version, "-v, --version", "Output the current version")
26
+ .helpOption("-h, --help", "Display help for command")
27
+ .option("-s, --severity <level>", "Severity of the issue (e.g. Critical, Major, Minor, Suggestion)")
28
+ .option("-t, --title <title>", "Title of the review")
29
+ .option("-i, --issue <issue>", "Description of the issue")
30
+ .option("-f, --fix <fix>", "Suggested fix")
31
+ .option("-o, --out <file>", "Save the output to a markdown file")
32
+ .action(async (options) => {
33
+ try {
34
+ console.log(
35
+ chalk.cyan("\nPRSmith - Professional PR Review Comment Generator\n")
36
+ );
16
37
 
17
- console.log(chalk.green("\nGenerated Comment:\n"));
18
- console.log(markdown);
19
- } catch (error) {
20
- if (error.name === "ExitPromptError") {
21
- console.log(chalk.yellow("\nYou have quit in b/w :) \n"));
22
- process.exit(0);
38
+ const config = loadConfig();
39
+ const data = await getReviewData(options, config);
40
+ const markdown = generateMarkdown(data, config);
41
+
42
+ console.log(chalk.green("\nGenerated Comment:\n"));
43
+ console.log(markdown);
44
+
45
+ clipboardy.writeSync(markdown);
46
+ console.log(chalk.green("✅ Comment copied to clipboard!\n"));
47
+
48
+ if (options.out) {
49
+ const outPath = path.resolve(process.cwd(), options.out);
50
+ fs.writeFileSync(outPath, markdown, "utf8");
51
+ console.log(chalk.green(`✅ Comment saved to ${outPath}\n`));
52
+ }
53
+ } catch (error) {
54
+ if (error.name === "ExitPromptError") {
55
+ console.log(chalk.yellow("\nYou have quit in b/w :) \n"));
56
+ process.exit(0);
57
+ }
58
+ console.error(chalk.red("\nSomething went wrong.\n"));
59
+ console.error(error);
60
+ process.exit(1);
23
61
  }
24
- console.error(chalk.red("\nSomething went wrong.\n"));
25
- console.error(error);
26
- process.exit(1);
27
- }
28
- }
62
+ });
29
63
 
30
- main();
64
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prsmith",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Forge professional pull request review comments from simple prompts.",
5
5
  "keywords": [
6
6
  "pull-request",
@@ -25,8 +25,10 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "chalk": "^5.6.2",
28
+ "clipboardy": "^5.3.1",
28
29
  "commander": "^15.0.0",
29
- "inquirer": "^14.0.1"
30
+ "inquirer": "^14.0.1",
31
+ "update-notifier": "^7.3.1"
30
32
  },
31
33
  "devDependencies": {
32
34
  "@eslint/js": "^10.0.1",
package/src/config.js ADDED
@@ -0,0 +1,28 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ export function loadConfig() {
6
+ const configPaths = [
7
+ path.join(os.homedir(), '.prsmith.json'),
8
+ path.join(process.cwd(), '.prsmith.json')
9
+ ];
10
+
11
+ let mergedConfig = { templates: {} };
12
+
13
+ for (const configPath of configPaths) {
14
+ if (fs.existsSync(configPath)) {
15
+ try {
16
+ const fileContent = fs.readFileSync(configPath, 'utf-8');
17
+ const parsed = JSON.parse(fileContent);
18
+ if (parsed.templates) {
19
+ mergedConfig.templates = { ...mergedConfig.templates, ...parsed.templates };
20
+ }
21
+ } catch (err) {
22
+ console.warn(`Warning: Could not parse config at ${configPath} - ${err.message}`);
23
+ }
24
+ }
25
+ }
26
+
27
+ return mergedConfig;
28
+ }
package/src/formatter.js CHANGED
@@ -1,8 +1,9 @@
1
- import { templates } from "./templates.js";
1
+ import { templates as defaultTemplates } from "./templates.js";
2
2
 
3
- export function generateMarkdown(data) {
3
+ export function generateMarkdown(data, config = {}) {
4
+ const mergedTemplates = { ...defaultTemplates, ...(config.templates || {}) };
4
5
  const intro =
5
- templates[data.severity] ||
6
+ mergedTemplates[data.severity] ||
6
7
  "The current implementation requires attention.";
7
8
 
8
9
  return `### ${data.severity}: ${data.title}
package/src/prompts.js CHANGED
@@ -1,27 +1,52 @@
1
1
  import inquirer from "inquirer";
2
2
 
3
- export async function getReviewData() {
4
- return inquirer.prompt([
5
- {
3
+ export async function getReviewData(options = {}, config = {}) {
4
+ const defaultSeverities = ["Critical", "Major", "Minor", "Suggestion"];
5
+ let severities = [...defaultSeverities];
6
+ if (config.templates) {
7
+ for (const key of Object.keys(config.templates)) {
8
+ if (!severities.includes(key)) {
9
+ severities.push(key);
10
+ }
11
+ }
12
+ }
13
+
14
+ const questions = [];
15
+
16
+ if (!options.severity) {
17
+ questions.push({
6
18
  type: "select",
7
19
  name: "severity",
8
20
  message: "Select severity:",
9
- choices: ["Critical", "Major", "Minor", "Suggestion"],
10
- },
11
- {
21
+ choices: severities,
22
+ });
23
+ }
24
+
25
+ if (!options.title) {
26
+ questions.push({
12
27
  type: "input",
13
28
  name: "title",
14
29
  message: "Review title:",
15
- },
16
- {
17
- type: "input",
30
+ });
31
+ }
32
+
33
+ if (!options.issue) {
34
+ questions.push({
35
+ type: "editor",
18
36
  name: "issue",
19
37
  message: "Describe the issue:",
20
- },
21
- {
22
- type: "input",
38
+ });
39
+ }
40
+
41
+ if (!options.fix) {
42
+ questions.push({
43
+ type: "editor",
23
44
  name: "fix",
24
45
  message: "Suggested fix:",
25
- },
26
- ]);
46
+ });
47
+ }
48
+
49
+ const answers = questions.length > 0 ? await inquirer.prompt(questions) : {};
50
+
51
+ return { ...options, ...answers };
27
52
  }
@@ -29,4 +29,23 @@ describe("formatter.js", () => {
29
29
  const markdown = generateMarkdown(data);
30
30
  expect(markdown).toContain("The current implementation requires attention.");
31
31
  });
32
+
33
+ it("should use custom templates when passed via config", () => {
34
+ const data = {
35
+ severity: "Nitpick",
36
+ title: "Formatting",
37
+ issue: "Indentation is off.",
38
+ fix: "Fix indentation."
39
+ };
40
+
41
+ const config = {
42
+ templates: {
43
+ Nitpick: "This is a tiny nitpick."
44
+ }
45
+ };
46
+
47
+ const markdown = generateMarkdown(data, config);
48
+ expect(markdown).toContain("### Nitpick: Formatting");
49
+ expect(markdown).toContain("This is a tiny nitpick.");
50
+ });
32
51
  });