gitpt 1.4.0 → 1.7.2

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 (116) hide show
  1. package/README.md +34 -160
  2. package/dist/commands/commit/commitFlags.js +7 -0
  3. package/dist/commands/commit/context/buildPrompt.js +16 -0
  4. package/dist/commands/commit/context/summaryPrompt.js +20 -0
  5. package/dist/commands/commit/context/systemPrompt.js +4 -1
  6. package/dist/commands/commit/context/userPrompt.js +4 -1
  7. package/dist/commands/commit/generateCommitMessage.js +16 -37
  8. package/dist/commands/commit/index.js +187 -178
  9. package/dist/commands/commit/summarizeDiff.js +193 -0
  10. package/dist/commands/config.js +24 -9
  11. package/dist/commands/hook/index.js +68 -0
  12. package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.js +20 -20
  13. package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.js +13 -10
  14. package/dist/commands/middleware/capabilitiesMiddleware/index.js +12 -11
  15. package/dist/commands/middleware/hasStagedChangesMiddleware.js +9 -6
  16. package/dist/commands/middleware/setupMiddleware/defaultModels.js +15 -0
  17. package/dist/commands/middleware/setupMiddleware/index.js +66 -38
  18. package/dist/commands/model.js +7 -4
  19. package/dist/commands/passthroughArgs.js +11 -0
  20. package/dist/commands/pr/context/systemPrompt.js +4 -1
  21. package/dist/commands/pr/context/userPrompt.js +4 -1
  22. package/dist/commands/pr/generatePRDetails.js +25 -31
  23. package/dist/commands/pr/getPRContext.js +37 -62
  24. package/dist/commands/pr/index.js +57 -62
  25. package/dist/commands/reset.js +26 -0
  26. package/dist/commands/review/index.js +31 -0
  27. package/dist/commands/setup.js +38 -13
  28. package/dist/config.js +63 -55
  29. package/dist/index.js +31 -62
  30. package/dist/llm/budget.js +10 -0
  31. package/dist/llm/index.js +12 -12
  32. package/dist/llm/providers/anthropic/index.js +31 -0
  33. package/dist/llm/providers/apiKey.js +41 -0
  34. package/dist/llm/providers/apple/client.js +77 -0
  35. package/dist/llm/providers/apple/index.js +69 -0
  36. package/dist/llm/providers/apple/models.js +29 -0
  37. package/dist/llm/providers/base.js +36 -0
  38. package/dist/llm/providers/local/index.js +84 -0
  39. package/dist/llm/providers/openai/index.js +19 -0
  40. package/dist/llm/providers/openaiCompatible.js +66 -0
  41. package/dist/llm/providers/openrouter/index.js +19 -0
  42. package/dist/llm/registry.js +39 -0
  43. package/dist/llm/setup/getAvailableModels.js +17 -0
  44. package/dist/llm/setup/selectModel.js +40 -0
  45. package/dist/llm/tokenCount.js +5 -0
  46. package/dist/package.js +67 -0
  47. package/dist/services/gh/createPullRequest.js +38 -58
  48. package/dist/services/gh/index.js +6 -3
  49. package/dist/services/gh/isAvailable.js +10 -8
  50. package/dist/services/git/executeGitAdd.js +11 -12
  51. package/dist/services/git/executeGitCommit.js +10 -11
  52. package/dist/services/git/getAmendChanges.js +23 -0
  53. package/dist/services/git/getChangedFiles.js +28 -61
  54. package/dist/services/git/getCommitsSinceBaseBranch.js +28 -56
  55. package/dist/services/git/getCurrentBranch.js +10 -8
  56. package/dist/services/git/getDefaultBranch.js +35 -60
  57. package/dist/services/git/getStagedChanges.js +10 -8
  58. package/dist/services/git/getStagedFiles.js +10 -9
  59. package/dist/services/git/hasStagedChanges.js +9 -8
  60. package/dist/services/git/index.js +17 -12
  61. package/dist/services/git/isAvailable.js +10 -8
  62. package/dist/services/git/isGitRepository.js +10 -8
  63. package/dist/utils/commitlint.js +97 -135
  64. package/dist/utils/formatBaseURL.js +7 -6
  65. package/dist/utils/maskApiKey.js +6 -7
  66. package/package.json +19 -5
  67. package/dist/commands/commit/context/systemPrompt.d.ts +0 -1
  68. package/dist/commands/commit/context/userPrompt.d.ts +0 -1
  69. package/dist/commands/commit/generateCommitMessage.d.ts +0 -1
  70. package/dist/commands/commit/index.d.ts +0 -7
  71. package/dist/commands/config.d.ts +0 -1
  72. package/dist/commands/middleware/capabilitiesMiddleware/ghCapability.d.ts +0 -1
  73. package/dist/commands/middleware/capabilitiesMiddleware/gitCapability.d.ts +0 -1
  74. package/dist/commands/middleware/capabilitiesMiddleware/index.d.ts +0 -3
  75. package/dist/commands/middleware/hasStagedChangesMiddleware.d.ts +0 -1
  76. package/dist/commands/middleware/setupMiddleware/getAvailableModels.d.ts +0 -4
  77. package/dist/commands/middleware/setupMiddleware/getAvailableModels.js +0 -11
  78. package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.d.ts +0 -1
  79. package/dist/commands/middleware/setupMiddleware/getOrUpdateApiKey.js +0 -39
  80. package/dist/commands/middleware/setupMiddleware/index.d.ts +0 -4
  81. package/dist/commands/middleware/setupMiddleware/selectModel.d.ts +0 -5
  82. package/dist/commands/middleware/setupMiddleware/selectModel.js +0 -38
  83. package/dist/commands/middleware/setupMiddleware/setupLocalLLM.d.ts +0 -5
  84. package/dist/commands/middleware/setupMiddleware/setupLocalLLM.js +0 -60
  85. package/dist/commands/middleware/setupMiddleware/setupOpenRouter.d.ts +0 -2
  86. package/dist/commands/middleware/setupMiddleware/setupOpenRouter.js +0 -66
  87. package/dist/commands/middleware/setupMiddleware/types.d.ts +0 -13
  88. package/dist/commands/middleware/setupMiddleware/types.js +0 -1
  89. package/dist/commands/model.d.ts +0 -1
  90. package/dist/commands/pr/context/systemPrompt.d.ts +0 -1
  91. package/dist/commands/pr/context/userPrompt.d.ts +0 -1
  92. package/dist/commands/pr/generatePRDetails.d.ts +0 -4
  93. package/dist/commands/pr/getPRContext.d.ts +0 -1
  94. package/dist/commands/pr/index.d.ts +0 -10
  95. package/dist/commands/setup.d.ts +0 -3
  96. package/dist/config.d.ts +0 -18
  97. package/dist/index.d.ts +0 -2
  98. package/dist/llm/index.d.ts +0 -5
  99. package/dist/services/gh/createPullRequest.d.ts +0 -1
  100. package/dist/services/gh/index.d.ts +0 -4
  101. package/dist/services/gh/isAvailable.d.ts +0 -1
  102. package/dist/services/git/executeGitAdd.d.ts +0 -1
  103. package/dist/services/git/executeGitCommit.d.ts +0 -1
  104. package/dist/services/git/getChangedFiles.d.ts +0 -1
  105. package/dist/services/git/getCommitsSinceBaseBranch.d.ts +0 -1
  106. package/dist/services/git/getCurrentBranch.d.ts +0 -1
  107. package/dist/services/git/getDefaultBranch.d.ts +0 -1
  108. package/dist/services/git/getStagedChanges.d.ts +0 -1
  109. package/dist/services/git/getStagedFiles.d.ts +0 -1
  110. package/dist/services/git/hasStagedChanges.d.ts +0 -1
  111. package/dist/services/git/index.d.ts +0 -13
  112. package/dist/services/git/isAvailable.d.ts +0 -1
  113. package/dist/services/git/isGitRepository.d.ts +0 -1
  114. package/dist/utils/commitlint.d.ts +0 -25
  115. package/dist/utils/formatBaseURL.d.ts +0 -1
  116. package/dist/utils/maskApiKey.d.ts +0 -1
@@ -1,66 +1,61 @@
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
1
  import { gh } from "../../services/gh/index.js";
6
2
  import { git } from "../../services/git/index.js";
3
+ import { capabilitiesMiddleware } from "../middleware/capabilitiesMiddleware/index.js";
4
+ import { setupMiddleware } from "../middleware/setupMiddleware/index.js";
7
5
  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
- }
6
+ import chalk from "chalk";
7
+ import inquirer from "inquirer";
8
+ //#region src/commands/pr/index.ts
9
+ var prCreateCommand = async (options = {}) => {
10
+ capabilitiesMiddleware(["git", "gh"]);
11
+ await setupMiddleware();
12
+ try {
13
+ const baseBranch = options.base || git.getDefaultBranch();
14
+ let title = options.title || "";
15
+ let body = options.body || "";
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
+ if (options.edit !== false) {
30
+ const answers = await inquirer.prompt([
31
+ {
32
+ type: "input",
33
+ name: "title",
34
+ message: "Edit PR title:",
35
+ default: title
36
+ },
37
+ {
38
+ type: "editor",
39
+ name: "body",
40
+ message: "Edit PR description:",
41
+ default: body
42
+ },
43
+ {
44
+ type: "confirm",
45
+ name: "draft",
46
+ message: "Create as draft PR?",
47
+ default: options.draft || false
48
+ }
49
+ ]);
50
+ title = answers.title;
51
+ body = answers.body;
52
+ const isDraft = answers.draft;
53
+ gh.createPullRequest(title, body, baseBranch, isDraft);
54
+ } else gh.createPullRequest(title, body, baseBranch, options.draft || false);
55
+ } catch (error) {
56
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
57
+ process.exit(1);
58
+ }
66
59
  };
60
+ //#endregion
61
+ export { prCreateCommand };
@@ -0,0 +1,26 @@
1
+ import { clearConfig, getConfig } from "../config.js";
2
+ import chalk from "chalk";
3
+ import inquirer from "inquirer";
4
+ //#region src/commands/reset.ts
5
+ var resetCommand = async (options = {}) => {
6
+ if (!Object.values(getConfig()).some((value) => value !== void 0)) {
7
+ console.log(chalk.gray("GitPT has no saved configuration to reset."));
8
+ return;
9
+ }
10
+ if (!options.yes) {
11
+ const { confirm } = await inquirer.prompt([{
12
+ type: "confirm",
13
+ name: "confirm",
14
+ message: "Reset GitPT? This clears the saved provider, model, and API key.",
15
+ default: false
16
+ }]);
17
+ if (!confirm) {
18
+ console.log(chalk.gray("Reset cancelled."));
19
+ return;
20
+ }
21
+ }
22
+ clearConfig();
23
+ console.log(chalk.green("✓ GitPT configuration reset. Run 'gitpt setup' to reconfigure."));
24
+ };
25
+ //#endregion
26
+ export { resetCommand };
@@ -0,0 +1,31 @@
1
+ import { git } from "../../services/git/index.js";
2
+ import { capabilitiesMiddleware } from "../middleware/capabilitiesMiddleware/index.js";
3
+ import { getProvider } from "../../llm/registry.js";
4
+ import { setupMiddleware } from "../middleware/setupMiddleware/index.js";
5
+ import chalk from "chalk";
6
+ //#region src/commands/review/index.ts
7
+ var REVIEW_SYSTEM = `You are a concise senior code reviewer. You are given a git diff of staged changes.
8
+ Respond with:
9
+ - one short sentence summarising what changed,
10
+ - then up to 5 brief bullet points flagging real risks, likely bugs, or concrete suggestions (drop a bullet if there's nothing worth saying).
11
+ Be specific. Skip praise and preamble.`;
12
+ var reviewCommand = async () => {
13
+ capabilitiesMiddleware(["git"]);
14
+ await setupMiddleware();
15
+ const diff = git.getStagedChanges();
16
+ if (!diff || !diff.trim()) {
17
+ console.log(chalk.yellow("No staged changes to review. Stage some with `git add` first."));
18
+ return;
19
+ }
20
+ console.log(chalk.blue("Reviewing staged changes..."));
21
+ const provider = getProvider();
22
+ const review = await provider.complete({
23
+ system: REVIEW_SYSTEM,
24
+ user: diff,
25
+ maxTokens: provider.maxOutputTokens
26
+ });
27
+ console.log("");
28
+ console.log(review.trim());
29
+ };
30
+ //#endregion
31
+ export { reviewCommand };
@@ -1,15 +1,40 @@
1
- import chalk from "chalk";
2
- import { clearConfig } from "../config.js";
1
+ import { clearConfig, saveConfig } from "../config.js";
2
+ import { getApiKey, saveApiKey } from "../llm/providers/apiKey.js";
3
+ import { getProviderClass } from "../llm/registry.js";
3
4
  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.`);
5
+ import chalk from "chalk";
6
+ //#region src/commands/setup.ts
7
+ var fail = (message) => {
8
+ console.error(chalk.red(`Error: ${message}`));
9
+ process.exit(1);
10
+ };
11
+ var headlessSetup = (options) => {
12
+ const spec = getProviderClass(options.provider);
13
+ if (!spec) return fail(`Unknown provider "${options.provider}". Valid: local, openrouter, openai, anthropic, apple.`);
14
+ if (!options.model) fail("--model is required.");
15
+ if (spec.requiresEndpoint && !options.endpoint) fail(`Provider "${spec.id}" requires --endpoint.`);
16
+ if (spec.requiresApiKey && !options.apiKey && !getApiKey()) fail(`Provider "${spec.id}" requires --api-key.`);
17
+ const config = {
18
+ provider: spec.id,
19
+ model: options.model
20
+ };
21
+ if (options.endpoint) config.customLLMEndpoint = options.endpoint;
22
+ saveConfig(config);
23
+ if (options.apiKey) saveApiKey(spec.id, options.apiKey);
24
+ console.log(chalk.green(`✓ Configured ${spec.label} with model ${options.model}.`));
25
+ };
26
+ var setupCommand = async (options = {}) => {
27
+ if (options.provider) {
28
+ headlessSetup(options);
29
+ return;
30
+ }
31
+ console.log(chalk.blue("GitPT Setup"));
32
+ console.log("This will configure GitPT to use an LLM for generating commit messages.");
33
+ console.log("");
34
+ if (options.clearConfig) clearConfig();
35
+ await setupMiddleware({ context: "setup" });
36
+ console.log("");
37
+ console.log(`Use ${chalk.cyan("gitpt commit")} to create commits with AI-generated messages.`);
15
38
  };
39
+ //#endregion
40
+ export { setupCommand };
package/dist/config.js CHANGED
@@ -1,58 +1,66 @@
1
1
  import chalk from "chalk";
2
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();
3
+ //#region src/config.ts
4
+ var config = new Configstore("gitpt");
5
+ var getConfig = () => {
6
+ try {
7
+ return {
8
+ provider: config.get("provider"),
9
+ customLLMEndpoint: config.get("customLLMEndpoint"),
10
+ model: config.get("model"),
11
+ apiKey: config.get("apiKey"),
12
+ apiKeys: config.get("apiKeys"),
13
+ contextWindow: config.get("contextWindow"),
14
+ debug: config.get("debug")
15
+ };
16
+ } catch (error) {
17
+ console.error(chalk.red("Error reading configuration:"), error);
18
+ return {};
19
+ }
58
20
  };
21
+ var saveConfig = (newConfig) => {
22
+ if (newConfig.provider !== void 0) config.set("provider", newConfig.provider);
23
+ if (newConfig.customLLMEndpoint !== void 0) config.set("customLLMEndpoint", newConfig.customLLMEndpoint);
24
+ if (newConfig.model !== void 0) config.set("model", newConfig.model);
25
+ if (newConfig.apiKey !== void 0) config.set("apiKey", newConfig.apiKey);
26
+ if (newConfig.apiKeys !== void 0) config.set("apiKeys", newConfig.apiKeys);
27
+ if (newConfig.contextWindow !== void 0) config.set("contextWindow", newConfig.contextWindow);
28
+ if (newConfig.debug !== void 0) config.set("debug", newConfig.debug);
29
+ };
30
+ /** Env proměnná je "zapnuto" pro libovolnou non-empty hodnotu kromě
31
+ * explicitně vypínajících ("0", "false", "no", "off"). */
32
+ var isTruthyEnv = (value) => {
33
+ if (!value) return false;
34
+ const v = value.trim().toLowerCase();
35
+ return v !== "" && ![
36
+ "0",
37
+ "false",
38
+ "no",
39
+ "off"
40
+ ].includes(v);
41
+ };
42
+ /** Debug mode: extra diagnostics (tokens, latency). Off by default; on via
43
+ * the `debug` config flag, the GITPT_DEBUG env var, or `--debug`. */
44
+ var isDebug = () => getConfig().debug === true || isTruthyEnv({}.GITPT_DEBUG);
45
+ var unsetConfigKey = (key) => {
46
+ config.delete(key);
47
+ };
48
+ var clearConfig = () => {
49
+ config.clear();
50
+ };
51
+ var ACCEPTED_DEFAULT_KEY = "acceptedDefault";
52
+ var getAcceptedDefault = () => {
53
+ try {
54
+ return config.get(ACCEPTED_DEFAULT_KEY);
55
+ } catch {
56
+ return;
57
+ }
58
+ };
59
+ var setAcceptedDefault = (id) => {
60
+ config.set(ACCEPTED_DEFAULT_KEY, id);
61
+ };
62
+ var clearAcceptedDefault = () => {
63
+ config.delete(ACCEPTED_DEFAULT_KEY);
64
+ };
65
+ //#endregion
66
+ export { clearAcceptedDefault, clearConfig, getAcceptedDefault, getConfig, isDebug, saveConfig, setAcceptedDefault, unsetConfigKey };
package/dist/index.js CHANGED
@@ -1,72 +1,41 @@
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" };
1
+ #!/usr/bin/env node
2
+ import package_default from "./package.js";
6
3
  import { commitCommand } from "./commands/commit/index.js";
7
4
  import { configCommand } from "./commands/config.js";
5
+ import { reviewCommand } from "./commands/review/index.js";
6
+ import { hookInstallCommand, hookRunCommand, hookUninstallCommand } from "./commands/hook/index.js";
8
7
  import { modelCommand } from "./commands/model.js";
9
8
  import { prCreateCommand } from "./commands/pr/index.js";
9
+ import { resetCommand } from "./commands/reset.js";
10
10
  import { setupCommand } from "./commands/setup.js";
11
- const program = new Command();
12
- program
13
- .name("gitpt")
14
- .description("Git Prompt Tool helps you write commit messages using AI")
15
- .version(packageJSON.version);
16
- // GitPT-specific commands
17
- program
18
- .command("setup")
19
- .description("Configure GitPT with your OpenRouter API key and model selection")
20
- .action(setupCommand);
21
- program
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")
28
- .action(modelCommand);
29
- // Enhanced git commands
30
- program
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")
36
- .allowUnknownOption(true) // Pass through other git commit options
37
- .action(commitCommand);
38
- program
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")
47
- .allowUnknownOption(true)
48
- .action(prCreateCommand);
49
- // Handle unknown commands by passing them to git
11
+ import chalk from "chalk";
12
+ import { spawnSync } from "child_process";
13
+ import { Command } from "commander";
14
+ //#region src/index.ts
15
+ var program = new Command();
16
+ program.name("gitpt").description("Git Prompt Tool helps you write commit messages using AI").version(package_default.version);
17
+ program.command("setup").description("Configure GitPT with your OpenRouter API key and model selection").option("--provider <id>", "Provider id (local, openrouter, openai, anthropic, apple)").option("--model <id>", "Model id").option("--endpoint <url>", "Custom LLM endpoint (for local)").option("--api-key <key>", "API key (for providers that need one)").action(setupCommand);
18
+ program.command("config").description("Configure GitPT with your OpenRouter API key and model selection").action(configCommand);
19
+ program.command("model").description("Change the AI model used for generating commit messages").action(modelCommand);
20
+ program.command("reset").description("Reset GitPT configuration (clears provider, model, and API key)").option("-y, --yes", "Skip the confirmation prompt").action(resetCommand);
21
+ program.command("commit").description("Generate AI-powered commit message based on staged changes").option("-m, --message <message>", "use provided message instead of generating one").option("-e, --edit", "edit the message after generation").option("--no-edit", "do not edit the message after generation").option("--dry-run", "generate and print the message but do not commit").option("--debug", "show diagnostics (tokens, latency) for this run").allowUnknownOption(true).allowExcessArguments(true).action(commitCommand);
22
+ program.command("pr create").description("Create a pull request with AI-generated title and description").option("-t, --title <title>", "Custom pull request title").option("-b, --body <body>", "Custom pull request description").option("-d, --draft", "Create as draft pull request").option("-B, --base <branch>", "Base branch to create PR against").option("-e, --edit", "Edit PR details before submission", true).option("--no-edit", "Skip editing PR details").allowUnknownOption(true).allowExcessArguments(true).action(prCreateCommand);
23
+ program.command("review").description("AI review of your staged changes (experimental)").action(reviewCommand);
24
+ var hook = program.command("hook").description("Manage the GitPT prepare-commit-msg git hook");
25
+ hook.command("install").description("Install the hook so `git commit` prefills an AI message").option("-f, --force", "Overwrite an existing prepare-commit-msg hook").action(hookInstallCommand);
26
+ hook.command("uninstall").description("Remove the GitPT prepare-commit-msg hook").action(hookUninstallCommand);
27
+ hook.command("run <msgFile> [source] [sha]").description("(internal) called by the installed hook").action(hookRunCommand);
50
28
  program.on("command:*", () => {
51
- try {
52
- // Get all arguments passed to the original command
53
- const args = process.argv.slice(2);
54
- // Execute git with all arguments
55
- execSync(`git ${args.join(" ")}`, { stdio: "inherit" });
56
- }
57
- catch (error) {
58
- // Git will handle its own error output through stdio: 'inherit'
59
- process.exit(1);
60
- }
29
+ const result = spawnSync("git", process.argv.slice(2), { stdio: "inherit" });
30
+ process.exit(result.status ?? 1);
61
31
  });
62
- // Main logic
63
32
  async function main() {
64
- try {
65
- await program.parseAsync();
66
- }
67
- catch (error) {
68
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
69
- process.exit(1);
70
- }
33
+ try {
34
+ await program.parseAsync();
35
+ } catch (error) {
36
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
37
+ process.exit(1);
38
+ }
71
39
  }
72
40
  main();
41
+ //#endregion
@@ -0,0 +1,10 @@
1
+ //#region src/llm/budget.ts
2
+ /** Rezerva: necháme 10 % použitelného okna jako bezpečnostní polštář. */
3
+ var MARGIN = .9;
4
+ /**
5
+ * Maximální počet tokenů promptu, který se vejde do `window`,
6
+ * když si necháme `reserved` tokenů na odpověď modelu.
7
+ */
8
+ var fitBudget = (window, reserved) => Math.floor((window - reserved) * MARGIN);
9
+ //#endregion
10
+ export { fitBudget };
package/dist/llm/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import openai from "openai";
2
- import { getConfig } from "../config.js";
3
1
  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, provider } = getConfig();
8
- const localLLMEndpoint = provider === "local" ? customLLMEndpoint : undefined;
9
- const baseURL = formatBaseURL(baseURLOverride ?? localLLMEndpoint ?? OPENROUTER_API_URL);
10
- return new openai.OpenAI({
11
- apiKey,
12
- baseURL,
13
- });
2
+ import openai from "openai";
3
+ //#region src/llm/index.ts
4
+ var OPENROUTER_API_URL = "https://openrouter.ai/api/v1";
5
+ var getLLMClient = (options) => {
6
+ const baseURL = formatBaseURL(options?.baseURLOverride ?? "https://openrouter.ai/api/v1");
7
+ const apiKey = options?.apiKey || "not-needed";
8
+ return new openai.OpenAI({
9
+ apiKey,
10
+ baseURL
11
+ });
14
12
  };
13
+ //#endregion
14
+ export { OPENROUTER_API_URL, getLLMClient };
@@ -0,0 +1,31 @@
1
+ import { OpenAICompatibleProvider, setupApiKeyProvider } from "../openaiCompatible.js";
2
+ //#region src/llm/providers/anthropic/index.ts
3
+ var ANTHROPIC_VERSION = "2023-06-01";
4
+ var listAnthropicModels = async (apiKey) => {
5
+ const response = await fetch("https://api.anthropic.com/v1/models?limit=100", { headers: {
6
+ "x-api-key": apiKey,
7
+ "anthropic-version": ANTHROPIC_VERSION
8
+ } });
9
+ if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
10
+ return ((await response.json())?.data ?? []).map((m) => ({
11
+ id: m.id,
12
+ name: m.display_name
13
+ }));
14
+ };
15
+ var AnthropicProvider = class AnthropicProvider extends OpenAICompatibleProvider {
16
+ static id = "anthropic";
17
+ static label = "Anthropic";
18
+ static baseURL = "https://api.anthropic.com/v1";
19
+ static setup(existingConfig) {
20
+ return setupApiKeyProvider(existingConfig, {
21
+ baseURL: AnthropicProvider.baseURL,
22
+ label: AnthropicProvider.label,
23
+ listModels: listAnthropicModels
24
+ });
25
+ }
26
+ baseURL() {
27
+ return AnthropicProvider.baseURL;
28
+ }
29
+ };
30
+ //#endregion
31
+ export { AnthropicProvider };
@@ -0,0 +1,41 @@
1
+ import { getConfig, saveConfig } from "../../config.js";
2
+ import { maskApiKey } from "../../utils/maskApiKey.js";
3
+ import inquirer from "inquirer";
4
+ //#region src/llm/providers/apiKey.ts
5
+ var getApiKey = () => {
6
+ const { provider, apiKeys, apiKey } = getConfig();
7
+ return provider && apiKeys?.[provider] || apiKey;
8
+ };
9
+ var saveApiKey = (providerId, key) => {
10
+ const { apiKeys } = getConfig();
11
+ saveConfig({ apiKeys: {
12
+ ...apiKeys,
13
+ [providerId]: key
14
+ } });
15
+ };
16
+ var promptApiKey = async (existingKey, label = "the provider") => {
17
+ if (existingKey) {
18
+ const { useExistingKey } = await inquirer.prompt([{
19
+ type: "list",
20
+ name: "useExistingKey",
21
+ message: `${label} API key:`,
22
+ choices: [{
23
+ name: `Use existing key (${maskApiKey(existingKey)})`,
24
+ value: true
25
+ }, {
26
+ name: "Enter a new API key",
27
+ value: false
28
+ }]
29
+ }]);
30
+ if (useExistingKey) return existingKey;
31
+ }
32
+ const { apiKey } = await inquirer.prompt([{
33
+ type: "input",
34
+ name: "apiKey",
35
+ message: `Enter your ${label} API key:`,
36
+ validate: (input) => input ? true : "API key is required"
37
+ }]);
38
+ return apiKey;
39
+ };
40
+ //#endregion
41
+ export { getApiKey, promptApiKey, saveApiKey };