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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
/**
|
|
3
|
+
* Show a list of models to select from
|
|
4
|
+
*/
|
|
5
|
+
export const selectModel = async (models, existingModel) => {
|
|
6
|
+
const modelChoices = models.map((model) => ({
|
|
7
|
+
name: model.name
|
|
8
|
+
? `${model.name} (Context: ${model.context_length})`
|
|
9
|
+
: model.id,
|
|
10
|
+
value: model.id,
|
|
11
|
+
}));
|
|
12
|
+
modelChoices.push({
|
|
13
|
+
name: "Other (specify model identifier)",
|
|
14
|
+
value: "custom",
|
|
15
|
+
});
|
|
16
|
+
const answers = await inquirer.prompt([
|
|
17
|
+
{
|
|
18
|
+
type: "list",
|
|
19
|
+
name: "modelChoice",
|
|
20
|
+
message: "Select an AI model:",
|
|
21
|
+
choices: modelChoices,
|
|
22
|
+
default: () => {
|
|
23
|
+
const currentIndex = modelChoices.findIndex((choice) => choice.value === existingModel);
|
|
24
|
+
return currentIndex >= 0 ? currentIndex : 0;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: "input",
|
|
29
|
+
name: "customModel",
|
|
30
|
+
message: "Enter model identifier:",
|
|
31
|
+
when: (answers) => answers.modelChoice === "custom",
|
|
32
|
+
validate: (input) => input ? true : "Model identifier is required",
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
return answers.modelChoice === "custom"
|
|
36
|
+
? answers.customModel
|
|
37
|
+
: answers.modelChoice;
|
|
38
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { saveConfig } from "../../../config.js";
|
|
4
|
+
import { getAvailableModels } from "./getAvailableModels.js";
|
|
5
|
+
import { selectModel } from "./selectModel.js";
|
|
6
|
+
/**
|
|
7
|
+
* Set up a local LLM configuration
|
|
8
|
+
*/
|
|
9
|
+
export const setupLocalLLM = async (existingConfig) => {
|
|
10
|
+
console.log(chalk.blue("Local LLM Setup"));
|
|
11
|
+
const endpointAnswer = await inquirer.prompt([
|
|
12
|
+
{
|
|
13
|
+
type: "input",
|
|
14
|
+
name: "localLLMEndpoint",
|
|
15
|
+
message: "Enter local LLM API endpoint (e.g., http://127.0.0.1:1234):",
|
|
16
|
+
default: existingConfig.customLLMEndpoint || "http://127.0.0.1:1234",
|
|
17
|
+
validate: (input) => {
|
|
18
|
+
if (!input)
|
|
19
|
+
return "API endpoint is required";
|
|
20
|
+
if (!input.startsWith("http://") && !input.startsWith("https://")) {
|
|
21
|
+
return "Must be a valid URL starting with http:// or https://";
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
console.log(chalk.gray("Trying to fetch available models from local LLM server..."));
|
|
28
|
+
const models = await getAvailableModels({
|
|
29
|
+
baseURLOverride: endpointAnswer.localLLMEndpoint,
|
|
30
|
+
});
|
|
31
|
+
let selectedModel;
|
|
32
|
+
if (models.length > 0) {
|
|
33
|
+
console.log(chalk.green(`✓ Found ${models.length} models available on your local LLM server`));
|
|
34
|
+
selectedModel = await selectModel(models, existingConfig.model);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log(chalk.yellow("Could not fetch models from local LLM server, please enter model name manually"));
|
|
38
|
+
const modelAnswer = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: "input",
|
|
41
|
+
name: "model",
|
|
42
|
+
message: "Enter model name to use with local endpoint:",
|
|
43
|
+
default: existingConfig.model,
|
|
44
|
+
validate: (input) => (input ? true : "Model name is required"),
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
selectedModel = modelAnswer.model;
|
|
48
|
+
}
|
|
49
|
+
const updatedConfig = {
|
|
50
|
+
...existingConfig,
|
|
51
|
+
provider: "local",
|
|
52
|
+
model: selectedModel,
|
|
53
|
+
customLLMEndpoint: endpointAnswer.localLLMEndpoint,
|
|
54
|
+
};
|
|
55
|
+
// Save the config
|
|
56
|
+
saveConfig(updatedConfig);
|
|
57
|
+
console.log(chalk.green("✓ Local LLM configuration saved"));
|
|
58
|
+
console.log(chalk.gray("Testing connection to local LLM..."));
|
|
59
|
+
return updatedConfig;
|
|
60
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { OPENROUTER_API_URL } from "../../../llm/index.js";
|
|
4
|
+
import { saveConfig } from "../../../config.js";
|
|
5
|
+
import { getAvailableModels } from "./getAvailableModels.js";
|
|
6
|
+
import { getOrUpdateApiKey } from "./getOrUpdateApiKey.js";
|
|
7
|
+
import { selectModel } from "./selectModel.js";
|
|
8
|
+
export const setupOpenRouter = async (existingConfig) => {
|
|
9
|
+
// Get API key - either the existing one or a new one
|
|
10
|
+
const apiKey = await getOrUpdateApiKey(existingConfig.apiKey);
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
console.error(chalk.red("API key is required for OpenRouter."));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Update the config with the potentially new API key
|
|
16
|
+
const updatedConfig = { ...existingConfig, apiKey };
|
|
17
|
+
// Display current model if any
|
|
18
|
+
if (updatedConfig.model) {
|
|
19
|
+
console.log("Current model:", chalk.yellow(updatedConfig.model));
|
|
20
|
+
console.log("");
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
console.log(chalk.gray("Fetching available models from OpenRouter..."));
|
|
24
|
+
const models = await getAvailableModels({
|
|
25
|
+
baseURLOverride: OPENROUTER_API_URL,
|
|
26
|
+
});
|
|
27
|
+
if (models.length > 0) {
|
|
28
|
+
console.log(chalk.green(`✓ Found ${models.length} models available with your API key`));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(chalk.yellow("No models found from OpenRouter. Please specify a model manually."));
|
|
32
|
+
}
|
|
33
|
+
const selectedModel = await selectModel(models, updatedConfig.model);
|
|
34
|
+
const finalConfig = {
|
|
35
|
+
...updatedConfig,
|
|
36
|
+
model: selectedModel,
|
|
37
|
+
useLocalLLM: false,
|
|
38
|
+
};
|
|
39
|
+
// Save the config
|
|
40
|
+
saveConfig(finalConfig);
|
|
41
|
+
console.log(chalk.green(`✓ Model set to: ${chalk.yellow(selectedModel)}`));
|
|
42
|
+
return finalConfig;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error(chalk.yellow(`Error fetching models: ${error}`));
|
|
46
|
+
// Fallback to manual input if API call fails
|
|
47
|
+
const modelAnswer = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: "input",
|
|
50
|
+
name: "model",
|
|
51
|
+
message: "Enter model identifier:",
|
|
52
|
+
validate: (input) => input ? true : "Model identifier is required",
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
const selectedModel = modelAnswer.model;
|
|
56
|
+
const finalConfig = {
|
|
57
|
+
...updatedConfig,
|
|
58
|
+
model: selectedModel,
|
|
59
|
+
useLocalLLM: false,
|
|
60
|
+
};
|
|
61
|
+
// Save the config
|
|
62
|
+
saveConfig(finalConfig);
|
|
63
|
+
console.log(chalk.green(`✓ Model set to: ${chalk.yellow(selectedModel)}`));
|
|
64
|
+
return finalConfig;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/commands/model.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const modelCommand: () => Promise<void>;
|
package/dist/commands/model.js
CHANGED
|
@@ -1,114 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{ name: 'Claude 3 Opus - Anthropic', value: 'anthropic/claude-3-opus:beta' },
|
|
8
|
-
{ name: 'Claude 3 Sonnet - Anthropic', value: 'anthropic/claude-3-sonnet:beta' },
|
|
9
|
-
{ name: 'Claude 3 Haiku - Anthropic', value: 'anthropic/claude-3-haiku:beta' },
|
|
10
|
-
{ name: 'GPT-4o - OpenAI', value: 'openai/gpt-4o' },
|
|
11
|
-
{ name: 'GPT-4 Turbo - OpenAI', value: 'openai/gpt-4-turbo' },
|
|
12
|
-
{ name: 'GPT-3.5 Turbo - OpenAI', value: 'openai/gpt-3.5-turbo' },
|
|
13
|
-
{ name: 'Other (specify model identifier)', value: 'custom' }
|
|
14
|
-
];
|
|
15
|
-
async function fetchAvailableModels(apiKey) {
|
|
16
|
-
try {
|
|
17
|
-
const response = await fetch('https://openrouter.ai/api/v1/models', {
|
|
18
|
-
headers: {
|
|
19
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
20
|
-
'HTTP-Referer': 'https://github.com/bartaxyz/GitPT',
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`);
|
|
25
|
-
}
|
|
26
|
-
const data = await response.json();
|
|
27
|
-
return data.data;
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
console.error(chalk.red('Error fetching models:'), error);
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
export async function modelCommand(modelId) {
|
|
35
|
-
console.log(chalk.blue('GitPT Model Selection'));
|
|
36
|
-
// Check if config exists
|
|
37
|
-
const existingConfig = getConfig();
|
|
38
|
-
if (!existingConfig) {
|
|
39
|
-
console.error(chalk.red('GitPT is not configured. Please run "gitpt setup" first.'));
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
let selectedModel;
|
|
43
|
-
// If a model ID is provided directly, use it
|
|
44
|
-
if (modelId) {
|
|
45
|
-
selectedModel = modelId;
|
|
46
|
-
// Update config with the new model while keeping the existing API key
|
|
47
|
-
saveConfig({
|
|
48
|
-
apiKey: existingConfig.apiKey,
|
|
49
|
-
model: selectedModel
|
|
50
|
-
});
|
|
51
|
-
console.log(chalk.green(`✓ Model set to: ${chalk.yellow(selectedModel)}`));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
// Otherwise, show interactive selection
|
|
55
|
-
console.log('Current model:', chalk.yellow(existingConfig.model));
|
|
56
|
-
console.log('');
|
|
57
|
-
try {
|
|
58
|
-
// Try to fetch available models from OpenRouter
|
|
59
|
-
console.log(chalk.gray('Fetching available models from OpenRouter...'));
|
|
60
|
-
const availableModels = await fetchAvailableModels(existingConfig.apiKey);
|
|
61
|
-
let modelChoices;
|
|
62
|
-
if (availableModels.length > 0) {
|
|
63
|
-
// Convert available models to choices format
|
|
64
|
-
modelChoices = availableModels.map(model => ({
|
|
65
|
-
name: `${model.name} (Context: ${model.context_length})`,
|
|
66
|
-
value: model.id
|
|
67
|
-
}));
|
|
68
|
-
// Add custom option at the end
|
|
69
|
-
modelChoices.push({ name: 'Other (specify model identifier)', value: 'custom' });
|
|
70
|
-
console.log(chalk.green(`✓ Found ${availableModels.length} models available with your API key`));
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
// Fallback to predefined list if API call fails
|
|
74
|
-
console.log(chalk.yellow('Could not fetch models from OpenRouter, using predefined list'));
|
|
75
|
-
modelChoices = POPULAR_MODELS;
|
|
76
|
-
}
|
|
77
|
-
const answers = await inquirer.prompt([
|
|
78
|
-
{
|
|
79
|
-
type: 'list',
|
|
80
|
-
name: 'modelChoice',
|
|
81
|
-
message: 'Select an AI model:',
|
|
82
|
-
choices: modelChoices,
|
|
83
|
-
default: () => {
|
|
84
|
-
// Try to find current model in the list to set as default
|
|
85
|
-
const currentIndex = modelChoices.findIndex(choice => choice.value === existingConfig.model);
|
|
86
|
-
return currentIndex >= 0 ? currentIndex : 0;
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
type: 'input',
|
|
91
|
-
name: 'customModel',
|
|
92
|
-
message: 'Enter model identifier:',
|
|
93
|
-
when: (answers) => answers.modelChoice === 'custom',
|
|
94
|
-
validate: (input) => {
|
|
95
|
-
if (!input)
|
|
96
|
-
return 'Model identifier is required';
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
]);
|
|
101
|
-
// Get the selected model
|
|
102
|
-
selectedModel = answers.modelChoice === 'custom' ? answers.customModel : answers.modelChoice;
|
|
103
|
-
// Save the updated configuration
|
|
104
|
-
saveConfig({
|
|
105
|
-
apiKey: existingConfig.apiKey,
|
|
106
|
-
model: selectedModel
|
|
107
|
-
});
|
|
108
|
-
console.log(chalk.green(`✓ Model updated to: ${chalk.yellow(selectedModel)}`));
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
console.error(chalk.red('Error updating model:'), error);
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { setupMiddleware } from "./middleware/setupMiddleware/index.js";
|
|
3
|
+
export const modelCommand = async () => {
|
|
4
|
+
console.log(chalk.blue("GitPT Model Selection"));
|
|
5
|
+
await setupMiddleware({ context: "model" });
|
|
6
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const systemPrompt = "\nYou are a helpful assistant that generates clear, informative GitHub pull request titles and descriptions.\n\nFor the title:\n- Keep it concise (under 80 characters)\n- Start with a verb in present tense (e.g., \"Add\", \"Fix\", \"Update\")\n- Clearly summarize the main purpose of the changes\n\nFor the description:\n- Start with a brief summary (1-2 sentences) of what the PR accomplishes\n- Include a more detailed explanation of changes if needed\n- List key changes as bullet points if there are multiple components\n- Include any relevant context that reviewers should know\n- End with any testing instructions if applicable\n\nFormat the description in Markdown with sections.\nDo not include \"PR\" or \"Pull Request\" in the title.\n";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const systemPrompt = `
|
|
2
|
+
You are a helpful assistant that generates clear, informative GitHub pull request titles and descriptions.
|
|
3
|
+
|
|
4
|
+
For the title:
|
|
5
|
+
- Keep it concise (under 80 characters)
|
|
6
|
+
- Start with a verb in present tense (e.g., "Add", "Fix", "Update")
|
|
7
|
+
- Clearly summarize the main purpose of the changes
|
|
8
|
+
|
|
9
|
+
For the description:
|
|
10
|
+
- Start with a brief summary (1-2 sentences) of what the PR accomplishes
|
|
11
|
+
- Include a more detailed explanation of changes if needed
|
|
12
|
+
- List key changes as bullet points if there are multiple components
|
|
13
|
+
- Include any relevant context that reviewers should know
|
|
14
|
+
- End with any testing instructions if applicable
|
|
15
|
+
|
|
16
|
+
Format the description in Markdown with sections.
|
|
17
|
+
Do not include "PR" or "Pull Request" in the title.
|
|
18
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const userPrompt = "\nGenerate a pull request title and description for the following changes:\n\nFormat your response exactly like this example:\nTitle: Add user authentication with JWT\nDescription: \n## Summary\nThis PR adds user authentication using JWT tokens.\n\n## Changes\n- Implement login and registration endpoints\n- Add JWT generation and validation\n- Update user model with password hashing\n- Add authorization middleware\n\n## How to test\n1. Register a new user with `/api/register`\n2. Login with the new user credentials\n3. Use the returned token to access protected endpoints\n";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const userPrompt = `
|
|
2
|
+
Generate a pull request title and description for the following changes:
|
|
3
|
+
|
|
4
|
+
Format your response exactly like this example:
|
|
5
|
+
Title: Add user authentication with JWT
|
|
6
|
+
Description:
|
|
7
|
+
## Summary
|
|
8
|
+
This PR adds user authentication using JWT tokens.
|
|
9
|
+
|
|
10
|
+
## Changes
|
|
11
|
+
- Implement login and registration endpoints
|
|
12
|
+
- Add JWT generation and validation
|
|
13
|
+
- Update user model with password hashing
|
|
14
|
+
- Add authorization middleware
|
|
15
|
+
|
|
16
|
+
## How to test
|
|
17
|
+
1. Register a new user with \`/api/register\`
|
|
18
|
+
2. Login with the new user credentials
|
|
19
|
+
3. Use the returned token to access protected endpoints
|
|
20
|
+
`;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getConfig } from "../../config.js";
|
|
3
|
+
import { getLLMClient } from "../../llm/index.js";
|
|
4
|
+
import { systemPrompt } from "./context/systemPrompt.js";
|
|
5
|
+
import { userPrompt } from "./context/userPrompt.js";
|
|
6
|
+
import { getPRContext } from "./getPRContext.js";
|
|
7
|
+
export const generatePRDetails = async () => {
|
|
8
|
+
const { model } = getConfig();
|
|
9
|
+
const context = getPRContext().join("\n\n");
|
|
10
|
+
const userPromptWithContext = [userPrompt, context].join("\n\n");
|
|
11
|
+
const llmClient = getLLMClient();
|
|
12
|
+
try {
|
|
13
|
+
const response = await llmClient.chat.completions.create({
|
|
14
|
+
model: model,
|
|
15
|
+
messages: [
|
|
16
|
+
{ role: "system", content: systemPrompt },
|
|
17
|
+
{ role: "user", content: userPromptWithContext },
|
|
18
|
+
],
|
|
19
|
+
max_completion_tokens: 1000,
|
|
20
|
+
});
|
|
21
|
+
const result = response.choices[0].message?.content?.trim();
|
|
22
|
+
if (!result) {
|
|
23
|
+
throw new Error("No response from LLM");
|
|
24
|
+
}
|
|
25
|
+
const titleMatch = result.match(/Title:\s*(.+?)(?:\n|$)/);
|
|
26
|
+
const descMatch = result.match(/Description:\s*\n([\s\S]+)$/);
|
|
27
|
+
const title = titleMatch ? titleMatch[1].trim() : "";
|
|
28
|
+
const body = descMatch ? descMatch[1].trim() : result;
|
|
29
|
+
return { title, body };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(chalk.red("Error generating PR details:"), error);
|
|
33
|
+
throw new Error("Failed to generate PR details");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getPRContext: () => string[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import { git } from "../../services/git/index.js";
|
|
4
|
+
export const getPRContext = () => {
|
|
5
|
+
const currentBranch = git.getCurrentBranch();
|
|
6
|
+
const baseBranch = git.getDefaultBranch();
|
|
7
|
+
// Get context for PR
|
|
8
|
+
const commitMessages = git.getCommitsSinceBaseBranch(baseBranch);
|
|
9
|
+
const changedFiles = git.getChangedFiles(baseBranch);
|
|
10
|
+
// Check if we have any content to work with
|
|
11
|
+
if (commitMessages.length === 0 && changedFiles.length === 0) {
|
|
12
|
+
console.log(chalk.yellow("No commits or changed files detected."));
|
|
13
|
+
console.log(chalk.yellow("Will attempt to generate PR details using branch name and repository context."));
|
|
14
|
+
}
|
|
15
|
+
// Get additional context from repository
|
|
16
|
+
let repoName = "";
|
|
17
|
+
let repoDescription = "";
|
|
18
|
+
try {
|
|
19
|
+
// Try to get repo information from GitHub CLI
|
|
20
|
+
const repoInfo = JSON.parse(execSync("gh repo view --json name,description").toString().trim());
|
|
21
|
+
repoName = repoInfo.name || "";
|
|
22
|
+
repoDescription = repoInfo.description || "";
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
// Continue without this info
|
|
26
|
+
}
|
|
27
|
+
console.log(chalk.blue("Generating PR title and description..."));
|
|
28
|
+
// Build a rich context for the AI
|
|
29
|
+
let contextSections = [
|
|
30
|
+
`Branch: ${currentBranch}`,
|
|
31
|
+
`Base branch: ${baseBranch}`,
|
|
32
|
+
];
|
|
33
|
+
// Add repository info if available
|
|
34
|
+
if (repoName) {
|
|
35
|
+
contextSections.push(`Repository: ${repoName}`);
|
|
36
|
+
}
|
|
37
|
+
if (repoDescription) {
|
|
38
|
+
contextSections.push(`Repository description: ${repoDescription}`);
|
|
39
|
+
}
|
|
40
|
+
// Add commit messages if available
|
|
41
|
+
if (commitMessages.length > 0) {
|
|
42
|
+
contextSections.push("Commit messages in this branch:", commitMessages.map((msg) => `- ${msg}`).join("\n"));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
contextSections.push("No commit messages available.");
|
|
46
|
+
// Try to extract intent from branch name if no commits
|
|
47
|
+
if (currentBranch.includes("/")) {
|
|
48
|
+
const branchParts = currentBranch.split("/");
|
|
49
|
+
const branchType = branchParts[0]; // e.g., "feature", "fix", "chore"
|
|
50
|
+
const branchDescription = branchParts
|
|
51
|
+
.slice(1)
|
|
52
|
+
.join("/")
|
|
53
|
+
.replace(/-/g, " ");
|
|
54
|
+
contextSections.push("Branch name analysis:", `Type: ${branchType}`, `Description: ${branchDescription}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Add changed files if available
|
|
58
|
+
if (changedFiles.length > 0) {
|
|
59
|
+
contextSections.push("Files changed in this branch:", changedFiles.map((file) => `- ${file}`).join("\n"));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
contextSections.push("No file changes detected.");
|
|
63
|
+
}
|
|
64
|
+
return contextSections;
|
|
65
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { capabilitiesMiddleware } from "../middleware/capabilitiesMiddleware/index.js";
|
|
4
|
+
import { setupMiddleware } from "../middleware/setupMiddleware/index.js";
|
|
5
|
+
import { gh } from "../../services/gh/index.js";
|
|
6
|
+
import { git } from "../../services/git/index.js";
|
|
7
|
+
import { generatePRDetails } from "./generatePRDetails.js";
|
|
8
|
+
export const prCreateCommand = async (options = {}) => {
|
|
9
|
+
capabilitiesMiddleware(["git", "gh"]);
|
|
10
|
+
await setupMiddleware();
|
|
11
|
+
try {
|
|
12
|
+
const baseBranch = options.base || git.getDefaultBranch();
|
|
13
|
+
let title = options.title || "";
|
|
14
|
+
let body = options.body || "";
|
|
15
|
+
// Generate PR details if not provided
|
|
16
|
+
if (!title || !body) {
|
|
17
|
+
const generatedDetails = await generatePRDetails();
|
|
18
|
+
title = title || generatedDetails.title;
|
|
19
|
+
body = body || generatedDetails.body;
|
|
20
|
+
console.log(chalk.green("✓ PR details generated"));
|
|
21
|
+
console.log("");
|
|
22
|
+
console.log(chalk.cyan("Title:"));
|
|
23
|
+
console.log(title);
|
|
24
|
+
console.log("");
|
|
25
|
+
console.log(chalk.cyan("Description:"));
|
|
26
|
+
console.log(body);
|
|
27
|
+
console.log("");
|
|
28
|
+
}
|
|
29
|
+
// Allow editing PR details
|
|
30
|
+
if (options.edit !== false) {
|
|
31
|
+
const answers = await inquirer.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: "input",
|
|
34
|
+
name: "title",
|
|
35
|
+
message: "Edit PR title:",
|
|
36
|
+
default: title,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "editor",
|
|
40
|
+
name: "body",
|
|
41
|
+
message: "Edit PR description:",
|
|
42
|
+
default: body,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "confirm",
|
|
46
|
+
name: "draft",
|
|
47
|
+
message: "Create as draft PR?",
|
|
48
|
+
default: options.draft || false,
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
title = answers.title;
|
|
52
|
+
body = answers.body;
|
|
53
|
+
const isDraft = answers.draft;
|
|
54
|
+
// Create the PR
|
|
55
|
+
gh.createPullRequest(title, body, baseBranch, isDraft);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Create the PR without editing
|
|
59
|
+
gh.createPullRequest(title, body, baseBranch, options.draft || false);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
};
|
package/dist/commands/setup.d.ts
CHANGED
package/dist/commands/setup.js
CHANGED
|
@@ -1,60 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
console.log('This will configure GitPT to use OpenRouter for generating commit messages.');
|
|
17
|
-
console.log('If you don\'t have an OpenRouter account yet, sign up at https://openrouter.ai');
|
|
18
|
-
console.log('');
|
|
19
|
-
const answers = await inquirer.prompt([
|
|
20
|
-
{
|
|
21
|
-
type: 'input',
|
|
22
|
-
name: 'apiKey',
|
|
23
|
-
message: 'Enter your OpenRouter API key:',
|
|
24
|
-
validate: (input) => {
|
|
25
|
-
if (!input)
|
|
26
|
-
return 'API key is required';
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
type: 'list',
|
|
32
|
-
name: 'modelChoice',
|
|
33
|
-
message: 'Select an AI model:',
|
|
34
|
-
choices: POPULAR_MODELS
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
type: 'input',
|
|
38
|
-
name: 'customModel',
|
|
39
|
-
message: 'Enter model identifier:',
|
|
40
|
-
when: (answers) => answers.modelChoice === 'custom',
|
|
41
|
-
validate: (input) => {
|
|
42
|
-
if (!input)
|
|
43
|
-
return 'Model identifier is required';
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
]);
|
|
48
|
-
// Clear existing config before saving new one
|
|
49
|
-
clearConfig();
|
|
50
|
-
// Save the new configuration
|
|
51
|
-
const model = answers.modelChoice === 'custom' ? answers.customModel : answers.modelChoice;
|
|
52
|
-
saveConfig({
|
|
53
|
-
apiKey: answers.apiKey,
|
|
54
|
-
model: model
|
|
55
|
-
});
|
|
56
|
-
console.log(chalk.green('✓ GitPT configuration saved successfully'));
|
|
57
|
-
console.log(`Model set to: ${chalk.yellow(model)}`);
|
|
58
|
-
console.log('');
|
|
59
|
-
console.log(`Use ${chalk.cyan('gitpt commit')} to create commits with AI-generated messages.`);
|
|
60
|
-
}
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { clearConfig } from "../config.js";
|
|
3
|
+
import { setupMiddleware } from "./middleware/setupMiddleware/index.js";
|
|
4
|
+
export const setupCommand = async (options = {}) => {
|
|
5
|
+
console.log(chalk.blue("GitPT Setup"));
|
|
6
|
+
console.log("This will configure GitPT to use an LLM for generating commit messages.");
|
|
7
|
+
console.log("You can use either OpenRouter (remote service) or a local LLM.");
|
|
8
|
+
console.log("");
|
|
9
|
+
if (options.clearConfig) {
|
|
10
|
+
clearConfig();
|
|
11
|
+
}
|
|
12
|
+
await setupMiddleware({ context: "setup" });
|
|
13
|
+
console.log("");
|
|
14
|
+
console.log(`Use ${chalk.cyan("gitpt commit")} to create commits with AI-generated messages.`);
|
|
15
|
+
};
|