gitpt 1.2.0 → 1.4.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 (100) hide show
  1. package/README.md +20 -10
  2. package/dist/commands/commit/context/systemPrompt.d.ts +1 -0
  3. package/dist/commands/commit/context/systemPrompt.js +38 -0
  4. package/dist/commands/commit/context/userPrompt.d.ts +1 -0
  5. package/dist/commands/commit/context/userPrompt.js +5 -0
  6. package/dist/commands/commit/generateCommitMessage.d.ts +1 -0
  7. package/dist/commands/commit/generateCommitMessage.js +39 -0
  8. package/dist/commands/{commit.d.ts → commit/index.d.ts} +1 -1
  9. package/dist/commands/commit/index.js +183 -0
  10. package/dist/commands/config.d.ts +1 -0
  11. package/dist/commands/config.js +11 -0
  12. package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.d.ts +1 -0
  13. package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.js +23 -0
  14. package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.d.ts +1 -0
  15. package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.js +12 -0
  16. package/dist/commands/middleware/capabilitiesMiddleware/index.d.ts +3 -0
  17. package/dist/commands/middleware/capabilitiesMiddleware/index.js +15 -0
  18. package/dist/commands/middleware/hasStagedChangesMiddleware.d.ts +1 -0
  19. package/dist/commands/middleware/hasStagedChangesMiddleware.js +8 -0
  20. package/dist/commands/middleware/setupMiddleware/getAvailableModels.d.ts +4 -0
  21. package/dist/commands/middleware/setupMiddleware/getAvailableModels.js +11 -0
  22. package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.d.ts +1 -0
  23. package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.js +39 -0
  24. package/dist/commands/middleware/setupMiddleware/index.d.ts +4 -0
  25. package/dist/commands/middleware/setupMiddleware/index.js +40 -0
  26. package/dist/commands/middleware/setupMiddleware/selectModel.d.ts +5 -0
  27. package/dist/commands/middleware/setupMiddleware/selectModel.js +38 -0
  28. package/dist/commands/middleware/setupMiddleware/setupLocalLLM.d.ts +5 -0
  29. package/dist/commands/middleware/setupMiddleware/setupLocalLLM.js +60 -0
  30. package/dist/commands/middleware/setupMiddleware/setupOpenRouter.d.ts +2 -0
  31. package/dist/commands/middleware/setupMiddleware/setupOpenRouter.js +66 -0
  32. package/dist/commands/middleware/setupMiddleware/types.d.ts +13 -0
  33. package/dist/commands/middleware/setupMiddleware/types.js +1 -0
  34. package/dist/commands/model.d.ts +1 -1
  35. package/dist/commands/model.js +6 -114
  36. package/dist/commands/pr/context/systemPrompt.d.ts +1 -0
  37. package/dist/commands/pr/context/systemPrompt.js +18 -0
  38. package/dist/commands/pr/context/userPrompt.d.ts +1 -0
  39. package/dist/commands/pr/context/userPrompt.js +22 -0
  40. package/dist/commands/pr/generatePRDetails.d.ts +4 -0
  41. package/dist/commands/pr/generatePRDetails.js +35 -0
  42. package/dist/commands/pr/getPRContext.d.ts +1 -0
  43. package/dist/commands/pr/getPRContext.js +65 -0
  44. package/dist/commands/{pr.d.ts → pr/index.d.ts} +1 -1
  45. package/dist/commands/pr/index.js +66 -0
  46. package/dist/commands/setup.d.ts +3 -1
  47. package/dist/commands/setup.js +15 -60
  48. package/dist/config.d.ts +18 -0
  49. package/dist/config.js +58 -0
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +37 -49
  52. package/dist/llm/index.d.ts +5 -0
  53. package/dist/llm/index.js +14 -0
  54. package/dist/services/gh/createPullRequest.d.ts +1 -0
  55. package/dist/services/gh/createPullRequest.js +63 -0
  56. package/dist/services/gh/index.d.ts +4 -0
  57. package/dist/services/gh/index.js +6 -0
  58. package/dist/services/gh/isAvailable.d.ts +1 -0
  59. package/dist/services/gh/isAvailable.js +10 -0
  60. package/dist/services/git/executeGitAdd.d.ts +1 -0
  61. package/dist/services/git/executeGitAdd.js +15 -0
  62. package/dist/services/git/executeGitCommit.d.ts +1 -0
  63. package/dist/services/git/executeGitCommit.js +12 -0
  64. package/dist/services/git/getChangedFiles.d.ts +1 -0
  65. package/dist/services/git/getChangedFiles.js +64 -0
  66. package/dist/services/git/getCommitsSinceBaseBranch.d.ts +1 -0
  67. package/dist/services/git/getCommitsSinceBaseBranch.js +59 -0
  68. package/dist/services/git/getCurrentBranch.d.ts +1 -0
  69. package/dist/services/git/getCurrentBranch.js +11 -0
  70. package/dist/services/git/getDefaultBranch.d.ts +1 -0
  71. package/dist/services/git/getDefaultBranch.js +63 -0
  72. package/dist/services/git/getStagedChanges.d.ts +1 -0
  73. package/dist/services/git/getStagedChanges.js +11 -0
  74. package/dist/services/git/getStagedFiles.d.ts +1 -0
  75. package/dist/services/git/getStagedFiles.js +12 -0
  76. package/dist/services/git/hasStagedChanges.d.ts +1 -0
  77. package/dist/services/git/hasStagedChanges.js +10 -0
  78. package/dist/services/git/index.d.ts +13 -0
  79. package/dist/services/git/index.js +24 -0
  80. package/dist/services/git/isAvailable.d.ts +1 -0
  81. package/dist/services/git/isAvailable.js +10 -0
  82. package/dist/services/git/isGitRepository.d.ts +1 -0
  83. package/dist/services/git/isGitRepository.js +10 -0
  84. package/dist/utils/commitlint.d.ts +4 -3
  85. package/dist/utils/commitlint.js +62 -38
  86. package/dist/utils/formatBaseURL.d.ts +1 -0
  87. package/dist/utils/formatBaseURL.js +7 -0
  88. package/dist/utils/maskApiKey.d.ts +1 -0
  89. package/dist/utils/maskApiKey.js +8 -0
  90. package/package.json +9 -10
  91. package/dist/commands/add.d.ts +0 -1
  92. package/dist/commands/add.js +0 -16
  93. package/dist/commands/commit.js +0 -99
  94. package/dist/commands/pr.js +0 -458
  95. package/dist/utils/api.d.ts +0 -1
  96. package/dist/utils/api.js +0 -61
  97. package/dist/utils/config.d.ts +0 -7
  98. package/dist/utils/config.js +0 -24
  99. package/dist/utils/git.d.ts +0 -6
  100. package/dist/utils/git.js +0 -62
@@ -0,0 +1 @@
1
+ export declare const isGitRepository: () => boolean;
@@ -0,0 +1,10 @@
1
+ import { execSync } from "child_process";
2
+ export const isGitRepository = () => {
3
+ try {
4
+ execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
5
+ return true;
6
+ }
7
+ catch (error) {
8
+ return false;
9
+ }
10
+ };
@@ -1,6 +1,3 @@
1
- /**
2
- * Represents a parsed commitlint configuration
3
- */
4
1
  export interface CommitlintConfig {
5
2
  rules?: Record<string, any>;
6
3
  extends?: string | string[];
@@ -9,6 +6,10 @@ export interface CommitlintConfig {
9
6
  * Check if a commitlint configuration exists in the repository
10
7
  */
11
8
  export declare function hasCommitlintConfig(): boolean;
9
+ /**
10
+ * Read commitlint config file (using @commitlint/load) and print it out
11
+ */
12
+ export declare function readCommitlintConfig(): Promise<any>;
12
13
  /**
13
14
  * Get the commitlint configuration format rules as a string
14
15
  */
@@ -1,23 +1,26 @@
1
- import fs from 'fs';
2
- import { execSync } from 'child_process';
1
+ import loadConfig from "@commitlint/load";
2
+ import { execSync } from "child_process";
3
+ import fs from "fs";
3
4
  /**
4
5
  * Check if a commitlint configuration exists in the repository
5
6
  */
6
7
  export function hasCommitlintConfig() {
7
8
  const possibleConfigFiles = [
8
- '.commitlintrc',
9
- '.commitlintrc.json',
10
- '.commitlintrc.yaml',
11
- '.commitlintrc.yml',
12
- '.commitlintrc.js',
13
- 'commitlint.config.js',
14
- 'package.json'
9
+ ".commitlintrc",
10
+ ".commitlintrc.json",
11
+ ".commitlintrc.yaml",
12
+ ".commitlintrc.yml",
13
+ ".commitlintrc.js",
14
+ "commitlint.config.js",
15
+ "package.json",
15
16
  ];
17
+ // Temporary
18
+ readCommitlintConfig();
16
19
  // Check if any of the possible config files exist
17
- return possibleConfigFiles.some(file => {
20
+ return possibleConfigFiles.some((file) => {
18
21
  try {
19
- if (file === 'package.json') {
20
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
22
+ if (file === "package.json") {
23
+ const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8"));
21
24
  return packageJson.commitlint !== undefined;
22
25
  }
23
26
  return fs.existsSync(file);
@@ -27,6 +30,14 @@ export function hasCommitlintConfig() {
27
30
  }
28
31
  });
29
32
  }
33
+ /**
34
+ * Read commitlint config file (using @commitlint/load) and print it out
35
+ */
36
+ export async function readCommitlintConfig() {
37
+ const config = await loadConfig();
38
+ // console.log(config);
39
+ return config.rules;
40
+ }
30
41
  /**
31
42
  * Get the commitlint configuration format rules as a string
32
43
  */
@@ -34,7 +45,9 @@ export function getCommitlintRules() {
34
45
  try {
35
46
  // Try to get the rules using commitlint CLI if available
36
47
  try {
37
- const rulesOutput = execSync('npx commitlint --print-config', { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
48
+ const rulesOutput = execSync("npx commitlint --print-config", {
49
+ stdio: ["ignore", "pipe", "ignore"],
50
+ }).toString();
38
51
  const config = JSON.parse(rulesOutput);
39
52
  return formatCommitlintRules(config);
40
53
  }
@@ -42,12 +55,12 @@ export function getCommitlintRules() {
42
55
  // If CLI approach fails, try to find and parse config files manually
43
56
  // This is a simplified approach - in a real implementation, you'd want to handle
44
57
  // all possible config files and formats
45
- if (fs.existsSync('commitlint.config.js')) {
58
+ if (fs.existsSync("commitlint.config.js")) {
46
59
  // We can't directly require the JS file in ESM, so we'll return a generic message
47
60
  return "Follow the conventional commit format (type(scope): message)";
48
61
  }
49
- if (fs.existsSync('.commitlintrc.json')) {
50
- const config = JSON.parse(fs.readFileSync('.commitlintrc.json', 'utf8'));
62
+ if (fs.existsSync(".commitlintrc.json")) {
63
+ const config = JSON.parse(fs.readFileSync(".commitlintrc.json", "utf8"));
51
64
  return formatCommitlintRules(config);
52
65
  }
53
66
  // Default to conventional commits format if we can't parse the config
@@ -68,22 +81,26 @@ function formatCommitlintRules(config) {
68
81
  return "Follow the conventional commit format (type(scope): message)";
69
82
  }
70
83
  // Extract type-enum rule if it exists
71
- if (config.rules['type-enum'] && Array.isArray(config.rules['type-enum'][2])) {
72
- const allowedTypes = config.rules['type-enum'][2];
73
- rulesDescription += `- Commit type must be one of: ${allowedTypes.join(', ')}\n`;
84
+ if (config.rules["type-enum"] &&
85
+ Array.isArray(config.rules["type-enum"][2])) {
86
+ const allowedTypes = config.rules["type-enum"][2];
87
+ rulesDescription += `- Commit type must be one of: ${allowedTypes.join(", ")}\n`;
74
88
  }
75
89
  // Extract other common rules
76
- if (config.rules['scope-enum'] && Array.isArray(config.rules['scope-enum'][2])) {
77
- const allowedScopes = config.rules['scope-enum'][2];
78
- rulesDescription += `- Scope must be one of: ${allowedScopes.join(', ')}\n`;
90
+ if (config.rules["scope-enum"] &&
91
+ Array.isArray(config.rules["scope-enum"][2])) {
92
+ const allowedScopes = config.rules["scope-enum"][2];
93
+ rulesDescription += `- Scope must be one of: ${allowedScopes.join(", ")}\n`;
79
94
  }
80
- if (config.rules['subject-case']) {
95
+ if (config.rules["subject-case"]) {
81
96
  rulesDescription += `- Subject must follow case rules\n`;
82
97
  }
83
- if (config.rules['subject-max-length']) {
84
- const maxLength = config.rules['subject-max-length'][2];
98
+ if (config.rules["subject-max-length"]) {
99
+ const maxLength = config.rules["subject-max-length"][2];
85
100
  rulesDescription += `- Subject must be no longer than ${maxLength} characters\n`;
86
101
  }
102
+ rulesDescription +=
103
+ "- Use a single commit message, not multiple messages separated by blank lines or markdown formatting";
87
104
  return rulesDescription;
88
105
  }
89
106
  /**
@@ -93,32 +110,39 @@ function formatCommitlintRules(config) {
93
110
  */
94
111
  export async function validateCommitMessage(message) {
95
112
  if (!hasCommitlintConfig()) {
96
- // If no commitlint config, consider it valid
113
+ // If no commitlint config exists, consider it valid
97
114
  return { valid: true };
98
115
  }
116
+ // Using CLI approach
99
117
  try {
100
118
  // Create a temporary file with the message
101
119
  const tempFile = `/tmp/gitpt-commit-msg-${Date.now()}`;
102
120
  fs.writeFileSync(tempFile, message);
103
121
  try {
104
- // Run commitlint against the file
105
- execSync(`npx commitlint --config commitlint.config.js < ${tempFile}`, { stdio: 'ignore' });
106
- // If we get here, validation passed
107
- fs.unlinkSync(tempFile); // Clean up temp file
122
+ execSync(`npx commitlint < ${tempFile}`, { stdio: "ignore" });
123
+ fs.unlinkSync(tempFile);
108
124
  return { valid: true };
109
125
  }
110
126
  catch (error) {
111
- // Capture the error output for feedback
112
- const errorOutput = execSync(`npx commitlint --config commitlint.config.js < ${tempFile} 2>&1 || true`).toString();
113
- fs.unlinkSync(tempFile); // Clean up temp file
114
- return {
115
- valid: false,
116
- errors: errorOutput
117
- };
127
+ // It's likely a validation error, capture the output
128
+ try {
129
+ const errorOutput = execSync(`npx commitlint < ${tempFile} 2>&1 || true`).toString();
130
+ fs.unlinkSync(tempFile);
131
+ return {
132
+ valid: false,
133
+ errors: errorOutput,
134
+ };
135
+ }
136
+ catch (e) {
137
+ // If we still can't get error output, fall back to basic pattern check
138
+ fs.unlinkSync(tempFile);
139
+ return { valid: true };
140
+ }
118
141
  }
119
142
  }
120
143
  catch (error) {
121
- // If we can't run commitlint, consider it valid to avoid blocking
144
+ // If all else fails, just do a basic regex check
145
+ console.warn("Warning: Could not validate with commitlint, performing basic validation");
122
146
  return { valid: true };
123
147
  }
124
148
  }
@@ -0,0 +1 @@
1
+ export declare const formatBaseURL: (baseURL: string) => string;
@@ -0,0 +1,7 @@
1
+ export const formatBaseURL = (baseURL) => {
2
+ // If it doesn't end with /v1, add it
3
+ if (!baseURL.endsWith("/v1")) {
4
+ return `${baseURL}/v1`;
5
+ }
6
+ return baseURL;
7
+ };
@@ -0,0 +1 @@
1
+ export declare const maskApiKey: (apiKey: string) => string;
@@ -0,0 +1,8 @@
1
+ export const maskApiKey = (apiKey) => {
2
+ if (apiKey.length <= 10) {
3
+ return "*".repeat(apiKey.length);
4
+ }
5
+ const firstFour = apiKey.substring(0, 4);
6
+ const lastFour = apiKey.substring(apiKey.length - 4);
7
+ return `${firstFour}...${lastFour}`;
8
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitpt",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "CLI tool that helps you write commit messages & pull request descriptions using AI",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -13,10 +13,9 @@
13
13
  "LICENSE"
14
14
  ],
15
15
  "scripts": {
16
+ "typecheck": "tsc --noEmit",
16
17
  "build": "tsc",
17
- "dev": "ts-node --esm src/index.ts",
18
- "start": "node dist/index.js",
19
- "test": "echo \"Error: no test specified\" && exit 1",
18
+ "test": "npm run typecheck",
20
19
  "prepublishOnly": "npm run build"
21
20
  },
22
21
  "repository": {
@@ -39,18 +38,18 @@
39
38
  "@types/inquirer": "^9.0.7",
40
39
  "@types/node": "^22.14.1",
41
40
  "@types/node-fetch": "^2.6.12",
42
- "ts-node": "^10.9.2",
41
+ "tsc-alias": "^1.8.16",
43
42
  "typescript": "^5.8.3"
44
43
  },
45
44
  "dependencies": {
45
+ "@commitlint/cli": "^19.8.1",
46
+ "@commitlint/config-conventional": "^19.8.1",
47
+ "@commitlint/load": "^19.8.1",
46
48
  "chalk": "^5.4.1",
47
49
  "commander": "^13.1.0",
48
50
  "configstore": "^7.0.0",
49
51
  "inquirer": "^12.5.2",
50
- "node-fetch": "^3.3.2"
51
- },
52
- "optionalDependencies": {
53
- "@commitlint/cli": "^18.4.3",
54
- "@commitlint/config-conventional": "^18.4.3"
52
+ "node-fetch": "^3.3.2",
53
+ "openai": "^4.100.0"
55
54
  }
56
55
  }
@@ -1 +0,0 @@
1
- export declare function addCommand(files: string[]): void;
@@ -1,16 +0,0 @@
1
- import chalk from 'chalk';
2
- import { isGitRepository, executeGitAdd } from '../utils/git.js';
3
- export function addCommand(files) {
4
- if (!isGitRepository()) {
5
- console.error(chalk.red('Error: Not a git repository'));
6
- process.exit(1);
7
- }
8
- try {
9
- executeGitAdd(files);
10
- console.log(chalk.green('Files added to staging area'));
11
- }
12
- catch (error) {
13
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
14
- process.exit(1);
15
- }
16
- }
@@ -1,99 +0,0 @@
1
- import inquirer from 'inquirer';
2
- import chalk from 'chalk';
3
- import { isGitRepository, hasStagedChanges, getStagedChanges, executeGitCommit } from '../utils/git.js';
4
- import { generateCommitMessage } from '../utils/api.js';
5
- import { getConfig } from '../utils/config.js';
6
- import { hasCommitlintConfig, validateCommitMessage } from '../utils/commitlint.js';
7
- export async function commitCommand(options) {
8
- if (!isGitRepository()) {
9
- console.error(chalk.red('Error: Not a git repository'));
10
- process.exit(1);
11
- }
12
- // Check if config exists
13
- const config = getConfig();
14
- if (!config) {
15
- console.error(chalk.red('GitPT is not configured. Please run "gitpt setup" first.'));
16
- process.exit(1);
17
- }
18
- // Check if there are staged changes
19
- if (!hasStagedChanges()) {
20
- console.error(chalk.yellow('No staged changes. Use "git add" or "gitpt add" to stage changes first.'));
21
- process.exit(1);
22
- }
23
- let commitMessage;
24
- // If message is provided, use that
25
- if (options.message) {
26
- commitMessage = options.message;
27
- }
28
- else {
29
- try {
30
- // Get staged changes
31
- const diff = getStagedChanges();
32
- console.log(chalk.blue('Generating commit message...'));
33
- // Check if commitlint is configured
34
- if (hasCommitlintConfig()) {
35
- console.log(chalk.blue('Commitlint configuration detected. Generating message according to rules...'));
36
- }
37
- // Generate commit message
38
- commitMessage = await generateCommitMessage(diff);
39
- // If commitlint is configured, validate the message
40
- if (hasCommitlintConfig()) {
41
- console.log(chalk.blue('Validating commit message against commitlint rules...'));
42
- const validation = await validateCommitMessage(commitMessage);
43
- if (!validation.valid && validation.errors) {
44
- console.log(chalk.yellow('Commit message failed validation. Regenerating...'));
45
- console.log(chalk.gray(validation.errors));
46
- // Regenerate with validation errors
47
- commitMessage = await generateCommitMessage(diff, validation.errors);
48
- // Validate again
49
- const revalidation = await validateCommitMessage(commitMessage);
50
- if (!revalidation.valid) {
51
- console.log(chalk.yellow('Warning: Regenerated message still has validation issues.'));
52
- console.log(chalk.gray(revalidation.errors));
53
- }
54
- }
55
- else {
56
- console.log(chalk.green('✓ Commit message passed validation'));
57
- }
58
- }
59
- console.log(chalk.green('✓ Commit message generated'));
60
- console.log('');
61
- console.log(chalk.cyan('Generated message:'));
62
- console.log(commitMessage);
63
- console.log('');
64
- }
65
- catch (error) {
66
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
67
- process.exit(1);
68
- }
69
- }
70
- // If edit is true or not specified, prompt user to edit the message
71
- if (options.edit !== false) {
72
- const answer = await inquirer.prompt([
73
- {
74
- type: 'editor',
75
- name: 'message',
76
- message: 'Edit commit message:',
77
- default: commitMessage
78
- }
79
- ]);
80
- commitMessage = answer.message;
81
- }
82
- // Extract other git options to pass through
83
- const gitOptions = Object.keys(options)
84
- .filter(key => !['message', 'edit'].includes(key))
85
- .map(key => {
86
- if (typeof options[key] === 'boolean') {
87
- return options[key] ? `--${key}` : `--no-${key}`;
88
- }
89
- return `--${key}=${options[key]}`;
90
- });
91
- try {
92
- executeGitCommit(commitMessage, gitOptions);
93
- console.log(chalk.green('✓ Changes committed successfully'));
94
- }
95
- catch (error) {
96
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
97
- process.exit(1);
98
- }
99
- }