gitpt 1.1.0 → 1.3.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 +52 -32
  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 +20 -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 +25 -0
  85. package/dist/utils/commitlint.js +148 -0
  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 -6
  91. package/dist/commands/add.d.ts +0 -1
  92. package/dist/commands/add.js +0 -16
  93. package/dist/commands/commit.js +0 -74
  94. package/dist/commands/pr.js +0 -458
  95. package/dist/utils/api.d.ts +0 -1
  96. package/dist/utils/api.js +0 -58
  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,18 @@
1
+ export interface GitPTConfig {
2
+ provider?: "openrouter" | "local";
3
+ customLLMEndpoint?: string;
4
+ model?: string;
5
+ apiKey?: string;
6
+ }
7
+ export declare const getConfig: () => GitPTConfig;
8
+ export declare const saveConfig: (newConfig: GitPTConfig) => void;
9
+ export declare enum ConfigErrors {
10
+ CustomLLMEndpointRequired = "Custom LLM endpoint is required for local LLM provider.",
11
+ APIKeyRequired = "API key is required for OpenRouter provider.",
12
+ ModelRequired = "Model is required."
13
+ }
14
+ export declare const validateConfig: () => {
15
+ isValid: boolean;
16
+ errors?: string[];
17
+ };
18
+ export declare const clearConfig: () => void;
package/dist/config.js ADDED
@@ -0,0 +1,58 @@
1
+ import chalk from "chalk";
2
+ import Configstore from "configstore";
3
+ const config = new Configstore("gitpt");
4
+ export const getConfig = () => {
5
+ try {
6
+ const provider = config.get("provider");
7
+ const customLLMEndpoint = config.get("customLLMEndpoint");
8
+ const model = config.get("model");
9
+ const apiKey = config.get("apiKey");
10
+ return {
11
+ provider,
12
+ customLLMEndpoint,
13
+ model,
14
+ apiKey,
15
+ };
16
+ }
17
+ catch (error) {
18
+ console.error(chalk.red("Error reading configuration:"), error);
19
+ return {};
20
+ }
21
+ };
22
+ export const saveConfig = (newConfig) => {
23
+ if (newConfig.provider !== undefined) {
24
+ config.set("provider", newConfig.provider);
25
+ }
26
+ if (newConfig.customLLMEndpoint !== undefined) {
27
+ config.set("customLLMEndpoint", newConfig.customLLMEndpoint);
28
+ }
29
+ if (newConfig.model !== undefined) {
30
+ config.set("model", newConfig.model);
31
+ }
32
+ if (newConfig.apiKey !== undefined) {
33
+ config.set("apiKey", newConfig.apiKey);
34
+ }
35
+ };
36
+ export var ConfigErrors;
37
+ (function (ConfigErrors) {
38
+ ConfigErrors["CustomLLMEndpointRequired"] = "Custom LLM endpoint is required for local LLM provider.";
39
+ ConfigErrors["APIKeyRequired"] = "API key is required for OpenRouter provider.";
40
+ ConfigErrors["ModelRequired"] = "Model is required.";
41
+ })(ConfigErrors || (ConfigErrors = {}));
42
+ export const validateConfig = () => {
43
+ const { provider, customLLMEndpoint, apiKey, model } = getConfig();
44
+ const errors = [];
45
+ if (provider === "local" && !customLLMEndpoint) {
46
+ errors.push(ConfigErrors.CustomLLMEndpointRequired);
47
+ }
48
+ if (provider === "openrouter" && !apiKey) {
49
+ errors.push(ConfigErrors.APIKeyRequired);
50
+ }
51
+ if (!model) {
52
+ errors.push(ConfigErrors.ModelRequired);
53
+ }
54
+ return { isValid: errors.length === 0, errors };
55
+ };
56
+ export const clearConfig = () => {
57
+ config.clear();
58
+ };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --experimental-specifier-resolution=node
2
2
  export {};
package/dist/index.js CHANGED
@@ -1,70 +1,58 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import chalk from 'chalk';
4
- import { execSync } from 'child_process';
5
- import { setupCommand } from './commands/setup.js';
6
- import { commitCommand } from './commands/commit.js';
7
- import { addCommand } from './commands/add.js';
8
- import { modelCommand } from './commands/model.js';
9
- import { prCreateCommand } from './commands/pr.js';
10
- import fs from 'fs';
11
- import path from 'path';
12
- import { fileURLToPath } from 'url';
13
- import { isGitRepository } from './utils/git.js';
14
- const __filename = fileURLToPath(import.meta.url);
15
- const __dirname = path.dirname(__filename);
16
- const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
17
- const version = packageJson.version;
1
+ #!/usr/bin/env node --experimental-specifier-resolution=node
2
+ import chalk from "chalk";
3
+ import { execSync } from "child_process";
4
+ import { Command } from "commander";
5
+ import packageJSON from "../package.json" with { type: "json" };
6
+ import { commitCommand } from "./commands/commit/index.js";
7
+ import { configCommand } from "./commands/config.js";
8
+ import { modelCommand } from "./commands/model.js";
9
+ import { prCreateCommand } from "./commands/pr/index.js";
10
+ import { setupCommand } from "./commands/setup.js";
18
11
  const program = new Command();
19
12
  program
20
- .name('gitpt')
21
- .description('Git Prompt Tool helps you write commit messages using AI')
22
- .version(version);
13
+ .name("gitpt")
14
+ .description("Git Prompt Tool helps you write commit messages using AI")
15
+ .version(packageJSON.version);
23
16
  // GitPT-specific commands
24
17
  program
25
- .command('setup')
26
- .description('Configure GitPT with your OpenRouter API key and model selection')
18
+ .command("setup")
19
+ .description("Configure GitPT with your OpenRouter API key and model selection")
27
20
  .action(setupCommand);
28
21
  program
29
- .command('model [model-id]')
30
- .description('Change the AI model used for generating commit messages')
22
+ .command("config")
23
+ .description("Configure GitPT with your OpenRouter API key and model selection")
24
+ .action(configCommand);
25
+ program
26
+ .command("model")
27
+ .description("Change the AI model used for generating commit messages")
31
28
  .action(modelCommand);
32
29
  // Enhanced git commands
33
30
  program
34
- .command('add [files...]')
35
- .description('Add files to git staging area (pass-through to git add)')
36
- .allowUnknownOption(true) // Pass through other git add options
37
- .action(addCommand);
38
- program
39
- .command('commit')
40
- .description('Generate AI-powered commit message based on staged changes')
41
- .option('-m, --message <message>', 'use provided message instead of generating one')
42
- .option('-e, --edit', 'edit the message after generation')
43
- .option('--no-edit', 'do not edit the message after generation')
31
+ .command("commit")
32
+ .description("Generate AI-powered commit message based on staged changes")
33
+ .option("-m, --message <message>", "use provided message instead of generating one")
34
+ .option("-e, --edit", "edit the message after generation")
35
+ .option("--no-edit", "do not edit the message after generation")
44
36
  .allowUnknownOption(true) // Pass through other git commit options
45
37
  .action(commitCommand);
46
38
  program
47
- .command('pr create')
48
- .description('Create a pull request with AI-generated title and description')
49
- .option('-t, --title <title>', 'Custom pull request title')
50
- .option('-b, --body <body>', 'Custom pull request description')
51
- .option('-d, --draft', 'Create as draft pull request')
52
- .option('-B, --base <branch>', 'Base branch to create PR against')
53
- .option('-e, --edit', 'Edit PR details before submission', true)
54
- .option('--no-edit', 'Skip editing PR details')
39
+ .command("pr create")
40
+ .description("Create a pull request with AI-generated title and description")
41
+ .option("-t, --title <title>", "Custom pull request title")
42
+ .option("-b, --body <body>", "Custom pull request description")
43
+ .option("-d, --draft", "Create as draft pull request")
44
+ .option("-B, --base <branch>", "Base branch to create PR against")
45
+ .option("-e, --edit", "Edit PR details before submission", true)
46
+ .option("--no-edit", "Skip editing PR details")
55
47
  .allowUnknownOption(true)
56
48
  .action(prCreateCommand);
57
49
  // Handle unknown commands by passing them to git
58
- program.on('command:*', (operands) => {
59
- if (!isGitRepository()) {
60
- console.error(chalk.red('Error: Not a git repository'));
61
- process.exit(1);
62
- }
50
+ program.on("command:*", () => {
63
51
  try {
64
52
  // Get all arguments passed to the original command
65
53
  const args = process.argv.slice(2);
66
54
  // Execute git with all arguments
67
- execSync(`git ${args.join(' ')}`, { stdio: 'inherit' });
55
+ execSync(`git ${args.join(" ")}`, { stdio: "inherit" });
68
56
  }
69
57
  catch (error) {
70
58
  // Git will handle its own error output through stdio: 'inherit'
@@ -77,7 +65,7 @@ async function main() {
77
65
  await program.parseAsync();
78
66
  }
79
67
  catch (error) {
80
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
68
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
81
69
  process.exit(1);
82
70
  }
83
71
  }
@@ -0,0 +1,5 @@
1
+ import openai from "openai";
2
+ export declare const OPENROUTER_API_URL = "https://openrouter.ai/api/v1";
3
+ export declare const getLLMClient: (options?: {
4
+ baseURLOverride?: string;
5
+ }) => openai;
@@ -0,0 +1,14 @@
1
+ import openai from "openai";
2
+ import { getConfig } from "../config.js";
3
+ import { formatBaseURL } from "../utils/formatBaseURL.js";
4
+ export const OPENROUTER_API_URL = "https://openrouter.ai/api/v1";
5
+ export const getLLMClient = (options) => {
6
+ const { baseURLOverride } = options || {};
7
+ const { apiKey, customLLMEndpoint } = getConfig();
8
+ const baseURL = formatBaseURL(baseURLOverride ?? customLLMEndpoint ?? OPENROUTER_API_URL);
9
+ console.log({ baseURL });
10
+ return new openai.OpenAI({
11
+ apiKey,
12
+ baseURL,
13
+ });
14
+ };
@@ -0,0 +1 @@
1
+ export declare const createPullRequest: (title: string, body: string, baseBranch: string, draft: boolean) => void;
@@ -0,0 +1,63 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const createPullRequest = (title, body, baseBranch, draft) => {
4
+ const draftFlag = draft ? "--draft" : "";
5
+ try {
6
+ console.log(chalk.blue(`Creating pull request to ${baseBranch}...`));
7
+ // Create a temporary file for the PR body to avoid issues with escaping
8
+ const tempFilePath = `/tmp/gitpt-pr-body-${Date.now()}.md`;
9
+ try {
10
+ // Write the body to a temporary file
11
+ execSync(`cat > "${tempFilePath}" << 'GITPT_EOF'
12
+ ${body}
13
+ GITPT_EOF`);
14
+ // Try to get the remote repo URL if available
15
+ let repoUrlArg = "";
16
+ try {
17
+ const repoUrl = execSync("git config --get remote.origin.url")
18
+ .toString()
19
+ .trim();
20
+ if (repoUrl) {
21
+ repoUrlArg = `--repo "${repoUrl}"`;
22
+ }
23
+ }
24
+ catch (e) {
25
+ // Proceed without repo URL
26
+ }
27
+ // Use the file for the body
28
+ const command = `gh pr create --title "${title.replace(/"/g, '\\"')}" --body-file "${tempFilePath}" --base "${baseBranch}" ${draftFlag} ${repoUrlArg}`;
29
+ // Set a timeout to avoid hanging indefinitely
30
+ console.log(chalk.gray("Running GitHub PR creation command..."));
31
+ console.log(chalk.gray(`Using base branch: ${baseBranch}`));
32
+ // Add debugging output
33
+ console.log(chalk.gray("Executing command with 60s timeout:"));
34
+ // Execute the command with a timeout
35
+ const result = execSync(command, {
36
+ stdio: "pipe",
37
+ timeout: 60000, // 60-second timeout
38
+ }).toString();
39
+ console.log(result);
40
+ console.log(chalk.green("✓ Pull request created successfully"));
41
+ }
42
+ finally {
43
+ // Clean up temporary file
44
+ try {
45
+ execSync(`rm -f "${tempFilePath}"`);
46
+ }
47
+ catch (e) {
48
+ // Ignore cleanup errors
49
+ }
50
+ }
51
+ }
52
+ catch (error) {
53
+ if (error instanceof Error && error.message.includes("timeout")) {
54
+ console.error(chalk.red("Error: GitHub CLI command timed out after 60 seconds."));
55
+ console.log(chalk.yellow("You may need to create the PR manually using:"));
56
+ console.log(chalk.yellow(`gh pr create --title "${title}" --base "${baseBranch}" ${draftFlag}`));
57
+ }
58
+ else {
59
+ console.error(chalk.red("Error creating pull request:"), error);
60
+ }
61
+ throw new Error("Failed to create pull request");
62
+ }
63
+ };
@@ -0,0 +1,4 @@
1
+ export declare const gh: {
2
+ createPullRequest: (title: string, body: string, baseBranch: string, draft: boolean) => void;
3
+ isAvailable: () => boolean;
4
+ };
@@ -0,0 +1,6 @@
1
+ import { createPullRequest } from "./createPullRequest.js";
2
+ import { isAvailable } from "./isAvailable.js";
3
+ export const gh = {
4
+ createPullRequest,
5
+ isAvailable,
6
+ };
@@ -0,0 +1 @@
1
+ export declare const isAvailable: () => boolean;
@@ -0,0 +1,10 @@
1
+ import { execSync } from "child_process";
2
+ export const isAvailable = () => {
3
+ try {
4
+ execSync("gh --version", { stdio: "ignore" });
5
+ return true;
6
+ }
7
+ catch (error) {
8
+ return false;
9
+ }
10
+ };
@@ -0,0 +1 @@
1
+ export declare const executeGitAdd: (files: string[]) => void;
@@ -0,0 +1,15 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const executeGitAdd = (files) => {
4
+ try {
5
+ if (files.length === 0) {
6
+ throw new Error("No files specified");
7
+ }
8
+ const fileArgs = files.join(" ");
9
+ execSync(`git add ${fileArgs}`, { stdio: "inherit" });
10
+ }
11
+ catch (error) {
12
+ console.error(chalk.red("Error adding files:"), error);
13
+ throw new Error("Failed to add files to git");
14
+ }
15
+ };
@@ -0,0 +1 @@
1
+ export declare const executeGitCommit: (message: string, additionalArgs?: string[]) => void;
@@ -0,0 +1,12 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const executeGitCommit = (message, additionalArgs = []) => {
4
+ try {
5
+ const args = additionalArgs.join(" ");
6
+ execSync(`git commit -m "${message}" ${args}`, { stdio: "inherit" });
7
+ }
8
+ catch (error) {
9
+ console.error(chalk.red("Error committing changes:"), error);
10
+ throw new Error("Failed to commit changes");
11
+ }
12
+ };
@@ -0,0 +1 @@
1
+ export declare const getChangedFiles: (baseBranch: string) => string[];
@@ -0,0 +1,64 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getChangedFiles = (baseBranch) => {
4
+ // Try several methods to get changed files
5
+ // Method 1: Compare with origin/baseBranch using three dots
6
+ try {
7
+ const changedFiles = execSync(`git diff --name-only origin/${baseBranch}...HEAD`)
8
+ .toString()
9
+ .trim();
10
+ if (changedFiles) {
11
+ return changedFiles.split("\n").filter(Boolean);
12
+ }
13
+ }
14
+ catch (error) {
15
+ // Continue to next method
16
+ }
17
+ // Method 2: Compare with local baseBranch using three dots
18
+ try {
19
+ const changedFiles = execSync(`git diff --name-only ${baseBranch}...HEAD`)
20
+ .toString()
21
+ .trim();
22
+ if (changedFiles) {
23
+ return changedFiles.split("\n").filter(Boolean);
24
+ }
25
+ }
26
+ catch (error) {
27
+ // Continue to next method
28
+ }
29
+ // Method 3: Direct comparison with two dots
30
+ try {
31
+ const changedFiles = execSync(`git diff --name-only ${baseBranch}..HEAD`)
32
+ .toString()
33
+ .trim();
34
+ if (changedFiles) {
35
+ return changedFiles.split("\n").filter(Boolean);
36
+ }
37
+ }
38
+ catch (error) {
39
+ // Continue to next method
40
+ }
41
+ // Method 4: Get recently modified files
42
+ try {
43
+ console.log(chalk.yellow(`Could not determine changed files relative to ${baseBranch}, using recently modified files...`));
44
+ const changedFiles = execSync("git ls-files --modified --others --exclude-standard")
45
+ .toString()
46
+ .trim();
47
+ if (changedFiles) {
48
+ return changedFiles.split("\n").filter(Boolean);
49
+ }
50
+ }
51
+ catch (error) {
52
+ // Last resort
53
+ }
54
+ // Method 5: List all files in the repo as a last resort
55
+ try {
56
+ console.log(chalk.yellow("Using all tracked files as fallback..."));
57
+ const allFiles = execSync("git ls-files").toString().trim();
58
+ return allFiles.split("\n").filter(Boolean).slice(0, 50); // Limit to first 50 files
59
+ }
60
+ catch (error) {
61
+ console.error(chalk.red("Could not determine changed files."));
62
+ return [];
63
+ }
64
+ };
@@ -0,0 +1 @@
1
+ export declare const getCommitsSinceBaseBranch: (baseBranch: string) => string[];
@@ -0,0 +1,59 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getCommitsSinceBaseBranch = (baseBranch) => {
4
+ try {
5
+ // Try first with origin/baseBranch
6
+ try {
7
+ const mergeBase = execSync(`git merge-base HEAD origin/${baseBranch}`)
8
+ .toString()
9
+ .trim();
10
+ const commitMessages = execSync(`git log --pretty=format:"%s" ${mergeBase}..HEAD`)
11
+ .toString()
12
+ .trim();
13
+ if (commitMessages) {
14
+ return commitMessages.split("\n").filter(Boolean);
15
+ }
16
+ }
17
+ catch (error) {
18
+ // If origin/baseBranch doesn't exist, try with just baseBranch
19
+ console.log(chalk.yellow(`No origin/${baseBranch} found, trying with local ${baseBranch} branch...`));
20
+ }
21
+ // Try with local branch
22
+ try {
23
+ const mergeBase = execSync(`git merge-base HEAD ${baseBranch}`)
24
+ .toString()
25
+ .trim();
26
+ const commitMessages = execSync(`git log --pretty=format:"%s" ${mergeBase}..HEAD`)
27
+ .toString()
28
+ .trim();
29
+ if (commitMessages) {
30
+ return commitMessages.split("\n").filter(Boolean);
31
+ }
32
+ }
33
+ catch (error) {
34
+ // If that fails too, fallback to simple branch comparison
35
+ console.log(chalk.yellow(`Merge base with ${baseBranch} not found, comparing branches directly...`));
36
+ }
37
+ // Direct branch comparison
38
+ try {
39
+ const commitMessages = execSync(`git log --pretty=format:"%s" ${baseBranch}..HEAD`)
40
+ .toString()
41
+ .trim();
42
+ if (commitMessages) {
43
+ return commitMessages.split("\n").filter(Boolean);
44
+ }
45
+ }
46
+ catch (error) {
47
+ console.log(chalk.yellow(`Could not compare with ${baseBranch}, using recent commits...`));
48
+ }
49
+ // Last resort: get most recent commits
50
+ const commitMessages = execSync('git log --pretty=format:"%s" -n 10')
51
+ .toString()
52
+ .trim();
53
+ return commitMessages.split("\n").filter(Boolean);
54
+ }
55
+ catch (error) {
56
+ console.error(chalk.yellow("Could not get commits. Using empty list."));
57
+ return [];
58
+ }
59
+ };
@@ -0,0 +1 @@
1
+ export declare const getCurrentBranch: () => string;
@@ -0,0 +1,11 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getCurrentBranch = () => {
4
+ try {
5
+ return execSync("git rev-parse --abbrev-ref HEAD").toString().trim();
6
+ }
7
+ catch (error) {
8
+ console.error(chalk.red("Error getting current branch:"), error);
9
+ throw new Error("Failed to get current branch");
10
+ }
11
+ };
@@ -0,0 +1 @@
1
+ export declare const getDefaultBranch: () => string;
@@ -0,0 +1,63 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getDefaultBranch = () => {
4
+ try {
5
+ // First check for a default branch set in git config
6
+ try {
7
+ const defaultBranch = execSync("git config init.defaultBranch")
8
+ .toString()
9
+ .trim();
10
+ if (defaultBranch) {
11
+ return defaultBranch;
12
+ }
13
+ }
14
+ catch (error) {
15
+ // Continue if git config doesn't have default branch
16
+ }
17
+ // Next, check if GitHub CLI can tell us the default branch
18
+ try {
19
+ const repoInfo = execSync("gh repo view --json defaultBranchRef --jq .defaultBranchRef.name")
20
+ .toString()
21
+ .trim();
22
+ if (repoInfo) {
23
+ return repoInfo;
24
+ }
25
+ }
26
+ catch (error) {
27
+ // Continue if gh command fails
28
+ }
29
+ // Try to find default branch in remote branches list
30
+ const branches = execSync("git branch -r").toString().trim().split("\n");
31
+ // Common default branch names, in order of likelihood
32
+ const mainPatterns = [
33
+ /origin\/main$/,
34
+ /origin\/master$/,
35
+ /origin\/develop$/,
36
+ /origin\/dev$/,
37
+ /origin\/trunk$/,
38
+ ];
39
+ // Try each pattern in order
40
+ for (const pattern of mainPatterns) {
41
+ const defaultBranch = branches.find((b) => pattern.test(b.trim()));
42
+ if (defaultBranch) {
43
+ return defaultBranch.trim().replace(/^origin\//, "");
44
+ }
45
+ }
46
+ // Check for a branch that has 'HEAD -> origin/' in it, indicating the default branch
47
+ const headBranch = branches.find((b) => b.includes("HEAD -> origin/"));
48
+ if (headBranch) {
49
+ const match = headBranch.match(/HEAD -> origin\/([^,\s]+)/);
50
+ if (match && match[1]) {
51
+ return match[1];
52
+ }
53
+ }
54
+ // Fallback to 'main' as most GitHub repos use this now
55
+ console.log(chalk.yellow('Could not determine default branch, using "main"'));
56
+ return "main";
57
+ }
58
+ catch (error) {
59
+ // If we can't determine, default to main
60
+ console.log(chalk.yellow('Error detecting default branch, using "main"'));
61
+ return "main";
62
+ }
63
+ };
@@ -0,0 +1 @@
1
+ export declare const getStagedChanges: () => string;
@@ -0,0 +1,11 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getStagedChanges = () => {
4
+ try {
5
+ return execSync("git diff --staged").toString();
6
+ }
7
+ catch (error) {
8
+ console.error(chalk.red("Error getting staged changes:"), error);
9
+ throw new Error("Failed to get staged changes");
10
+ }
11
+ };
@@ -0,0 +1 @@
1
+ export declare const getStagedFiles: () => string[];
@@ -0,0 +1,12 @@
1
+ import chalk from "chalk";
2
+ import { execSync } from "child_process";
3
+ export const getStagedFiles = () => {
4
+ try {
5
+ const result = execSync("git diff --staged --name-only").toString();
6
+ return result.split("\n").filter(Boolean);
7
+ }
8
+ catch (error) {
9
+ console.error(chalk.red("Error getting staged files:"), error);
10
+ throw new Error("Failed to get staged files");
11
+ }
12
+ };
@@ -0,0 +1 @@
1
+ export declare const hasStagedChanges: () => boolean;
@@ -0,0 +1,10 @@
1
+ import { execSync } from "child_process";
2
+ export const hasStagedChanges = () => {
3
+ try {
4
+ const output = execSync('git diff --staged --quiet || echo "has-changes"').toString();
5
+ return output.includes("has-changes");
6
+ }
7
+ catch (error) {
8
+ return true; // Assume there are changes if we can't check
9
+ }
10
+ };
@@ -0,0 +1,13 @@
1
+ export declare const git: {
2
+ add: (files: string[]) => void;
3
+ commit: (message: string, additionalArgs?: string[]) => void;
4
+ getChangedFiles: (baseBranch: string) => string[];
5
+ getCommitsSinceBaseBranch: (baseBranch: string) => string[];
6
+ getCurrentBranch: () => string;
7
+ getDefaultBranch: () => string;
8
+ hasStagedChanges: () => boolean;
9
+ getStagedChanges: () => string;
10
+ getStagedFiles: () => string[];
11
+ isAvailable: () => boolean;
12
+ isGitRepository: () => boolean;
13
+ };