prsmith 1.0.2 → 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
@@ -45,30 +45,53 @@ Install globally to use it anywhere on your machine.
45
45
  npm install -g prsmith
46
46
  ```
47
47
 
48
- ## Features
48
+ ## ✨ Advanced Features (v1.1.0)
49
49
 
50
- - **Interactive Prompts:** No need to memorize complex flags. Just run the tool and answer the prompts.
51
- - **Smart Formatting:** Automatically generates perfectly structured Markdown.
52
- - **Graceful Exits:** Hit `Ctrl+C` anytime to exit safely without stack traces.
53
- - **Built-in Help:** Run `prsmith --help` to view documentation directly 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.
54
55
 
55
- ## Usage
56
+ ## 💻 Usage
56
57
 
57
- ### Standard Mode
58
+ ### Interactive Mode
58
59
  The primary way to use PRSmith is via its interactive mode. Simply run:
59
60
 
60
61
  ```bash
61
62
  prsmith
62
63
  ```
63
- This will launch the interactive prompt asking for Severity, Title, Issue, and Fix.
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!
64
65
 
65
- ### Commands & Flags
66
+ ### Non-Interactive Flags
66
67
 
67
- | Command | Description |
68
- | :--- | :--- |
69
- | `prsmith` | Launch the interactive generator |
70
- | `prsmith -h`, `--help` | Display the help menu and commands |
71
- | `prsmith -v`, `--version` | Print the current installed version |
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!
72
95
 
73
96
  <details>
74
97
  <summary><b>Click to view an Example Interaction</b></summary>
package/bin/cli.js CHANGED
@@ -1,27 +1,55 @@
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";
4
7
  import { program } from "commander";
8
+ import clipboardy from "clipboardy";
9
+ import updateNotifier from "update-notifier";
5
10
  import { getReviewData } from "../src/prompts.js";
6
11
  import { generateMarkdown } from "../src/formatter.js";
12
+ import { loadConfig } from "../src/config.js";
13
+
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
+ );
19
+
20
+ updateNotifier({ pkg }).notify();
7
21
 
8
22
  program
9
23
  .name("prsmith")
10
24
  .description("Forge professional pull request review comments directly from the terminal.")
11
- .version("1.0.1", "-v, --version", "Output the current version")
25
+ .version(pkg.version, "-v, --version", "Output the current version")
12
26
  .helpOption("-h, --help", "Display help for command")
13
- .action(async () => {
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) => {
14
33
  try {
15
34
  console.log(
16
35
  chalk.cyan("\nPRSmith - Professional PR Review Comment Generator\n")
17
36
  );
18
37
 
19
- const data = await getReviewData();
20
-
21
- const markdown = generateMarkdown(data);
38
+ const config = loadConfig();
39
+ const data = await getReviewData(options, config);
40
+ const markdown = generateMarkdown(data, config);
22
41
 
23
42
  console.log(chalk.green("\nGenerated Comment:\n"));
24
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
+ }
25
53
  } catch (error) {
26
54
  if (error.name === "ExitPromptError") {
27
55
  console.log(chalk.yellow("\nYou have quit in b/w :) \n"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prsmith",
3
- "version": "1.0.2",
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
  });