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.
- package/README.md +52 -32
- package/dist/commands/commit/context/systemPrompt.d.ts +1 -0
- package/dist/commands/commit/context/systemPrompt.js +38 -0
- package/dist/commands/commit/context/userPrompt.d.ts +1 -0
- package/dist/commands/commit/context/userPrompt.js +5 -0
- package/dist/commands/commit/generateCommitMessage.d.ts +1 -0
- package/dist/commands/commit/generateCommitMessage.js +39 -0
- package/dist/commands/{commit.d.ts → commit/index.d.ts} +1 -1
- package/dist/commands/commit/index.js +183 -0
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +11 -0
- package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.d.ts +1 -0
- package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.js +23 -0
- package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.d.ts +1 -0
- package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.js +12 -0
- package/dist/commands/middleware/capabilitiesMiddleware/index.d.ts +3 -0
- package/dist/commands/middleware/capabilitiesMiddleware/index.js +15 -0
- package/dist/commands/middleware/hasStagedChangesMiddleware.d.ts +1 -0
- package/dist/commands/middleware/hasStagedChangesMiddleware.js +8 -0
- package/dist/commands/middleware/setupMiddleware/getAvailableModels.d.ts +4 -0
- package/dist/commands/middleware/setupMiddleware/getAvailableModels.js +11 -0
- package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.d.ts +1 -0
- package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.js +39 -0
- package/dist/commands/middleware/setupMiddleware/index.d.ts +4 -0
- package/dist/commands/middleware/setupMiddleware/index.js +40 -0
- package/dist/commands/middleware/setupMiddleware/selectModel.d.ts +5 -0
- package/dist/commands/middleware/setupMiddleware/selectModel.js +38 -0
- package/dist/commands/middleware/setupMiddleware/setupLocalLLM.d.ts +5 -0
- package/dist/commands/middleware/setupMiddleware/setupLocalLLM.js +60 -0
- package/dist/commands/middleware/setupMiddleware/setupOpenRouter.d.ts +2 -0
- package/dist/commands/middleware/setupMiddleware/setupOpenRouter.js +66 -0
- package/dist/commands/middleware/setupMiddleware/types.d.ts +13 -0
- package/dist/commands/middleware/setupMiddleware/types.js +1 -0
- package/dist/commands/model.d.ts +1 -1
- package/dist/commands/model.js +6 -114
- package/dist/commands/pr/context/systemPrompt.d.ts +1 -0
- package/dist/commands/pr/context/systemPrompt.js +18 -0
- package/dist/commands/pr/context/userPrompt.d.ts +1 -0
- package/dist/commands/pr/context/userPrompt.js +20 -0
- package/dist/commands/pr/generatePRDetails.d.ts +4 -0
- package/dist/commands/pr/generatePRDetails.js +35 -0
- package/dist/commands/pr/getPRContext.d.ts +1 -0
- package/dist/commands/pr/getPRContext.js +65 -0
- package/dist/commands/{pr.d.ts → pr/index.d.ts} +1 -1
- package/dist/commands/pr/index.js +66 -0
- package/dist/commands/setup.d.ts +3 -1
- package/dist/commands/setup.js +15 -60
- package/dist/config.d.ts +18 -0
- package/dist/config.js +58 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -49
- package/dist/llm/index.d.ts +5 -0
- package/dist/llm/index.js +14 -0
- package/dist/services/gh/createPullRequest.d.ts +1 -0
- package/dist/services/gh/createPullRequest.js +63 -0
- package/dist/services/gh/index.d.ts +4 -0
- package/dist/services/gh/index.js +6 -0
- package/dist/services/gh/isAvailable.d.ts +1 -0
- package/dist/services/gh/isAvailable.js +10 -0
- package/dist/services/git/executeGitAdd.d.ts +1 -0
- package/dist/services/git/executeGitAdd.js +15 -0
- package/dist/services/git/executeGitCommit.d.ts +1 -0
- package/dist/services/git/executeGitCommit.js +12 -0
- package/dist/services/git/getChangedFiles.d.ts +1 -0
- package/dist/services/git/getChangedFiles.js +64 -0
- package/dist/services/git/getCommitsSinceBaseBranch.d.ts +1 -0
- package/dist/services/git/getCommitsSinceBaseBranch.js +59 -0
- package/dist/services/git/getCurrentBranch.d.ts +1 -0
- package/dist/services/git/getCurrentBranch.js +11 -0
- package/dist/services/git/getDefaultBranch.d.ts +1 -0
- package/dist/services/git/getDefaultBranch.js +63 -0
- package/dist/services/git/getStagedChanges.d.ts +1 -0
- package/dist/services/git/getStagedChanges.js +11 -0
- package/dist/services/git/getStagedFiles.d.ts +1 -0
- package/dist/services/git/getStagedFiles.js +12 -0
- package/dist/services/git/hasStagedChanges.d.ts +1 -0
- package/dist/services/git/hasStagedChanges.js +10 -0
- package/dist/services/git/index.d.ts +13 -0
- package/dist/services/git/index.js +24 -0
- package/dist/services/git/isAvailable.d.ts +1 -0
- package/dist/services/git/isAvailable.js +10 -0
- package/dist/services/git/isGitRepository.d.ts +1 -0
- package/dist/services/git/isGitRepository.js +10 -0
- package/dist/utils/commitlint.d.ts +25 -0
- package/dist/utils/commitlint.js +148 -0
- package/dist/utils/formatBaseURL.d.ts +1 -0
- package/dist/utils/formatBaseURL.js +7 -0
- package/dist/utils/maskApiKey.d.ts +1 -0
- package/dist/utils/maskApiKey.js +8 -0
- package/package.json +9 -6
- package/dist/commands/add.d.ts +0 -1
- package/dist/commands/add.js +0 -16
- package/dist/commands/commit.js +0 -74
- package/dist/commands/pr.js +0 -458
- package/dist/utils/api.d.ts +0 -1
- package/dist/utils/api.js +0 -58
- package/dist/utils/config.d.ts +0 -7
- package/dist/utils/config.js +0 -24
- package/dist/utils/git.d.ts +0 -6
- package/dist/utils/git.js +0 -62
package/dist/config.d.ts
ADDED
|
@@ -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
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { commitCommand } from
|
|
7
|
-
import {
|
|
8
|
-
import { modelCommand } from
|
|
9
|
-
import { prCreateCommand } from
|
|
10
|
-
import
|
|
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(
|
|
21
|
-
.description(
|
|
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(
|
|
26
|
-
.description(
|
|
18
|
+
.command("setup")
|
|
19
|
+
.description("Configure GitPT with your OpenRouter API key and model selection")
|
|
27
20
|
.action(setupCommand);
|
|
28
21
|
program
|
|
29
|
-
.command(
|
|
30
|
-
.description(
|
|
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(
|
|
35
|
-
.description(
|
|
36
|
-
.
|
|
37
|
-
.
|
|
38
|
-
|
|
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(
|
|
48
|
-
.description(
|
|
49
|
-
.option(
|
|
50
|
-
.option(
|
|
51
|
-
.option(
|
|
52
|
-
.option(
|
|
53
|
-
.option(
|
|
54
|
-
.option(
|
|
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(
|
|
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(
|
|
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(
|
|
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,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 @@
|
|
|
1
|
+
export declare const isAvailable: () => boolean;
|
|
@@ -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
|
+
};
|