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
@@ -0,0 +1,77 @@
1
+ import { spawn } from "child_process";
2
+ var clean = (text) => text.replace(/\x1b\[[0-9;]*m/g, "").replace(/[⠀-⣿]/g, "").trim();
3
+ var messageText = (content) => {
4
+ if (typeof content === "string") return content;
5
+ if (Array.isArray(content)) return content.map((part) => part.type === "text" ? part.text : "").join("");
6
+ return "";
7
+ };
8
+ var runFm = (args, stdin) => new Promise((resolve, reject) => {
9
+ const child = spawn("fm", args, { stdio: [
10
+ "pipe",
11
+ "pipe",
12
+ "pipe"
13
+ ] });
14
+ let stdout = "";
15
+ let stderr = "";
16
+ child.stdout.on("data", (chunk) => {
17
+ stdout += chunk.toString();
18
+ });
19
+ child.stderr.on("data", (chunk) => {
20
+ stderr += chunk.toString();
21
+ });
22
+ child.on("error", (error) => {
23
+ if (error.code === "ENOENT") {
24
+ reject(/* @__PURE__ */ new Error("The Apple Foundation Models CLI ('fm') was not found. It ships with macOS 27 and later."));
25
+ return;
26
+ }
27
+ reject(error);
28
+ });
29
+ child.on("close", (code) => {
30
+ const out = stdout.trim();
31
+ const err = clean(stderr);
32
+ if (code !== 0 || !out) {
33
+ reject(new Error(err || out || `'fm' exited with code ${code} and no output`));
34
+ return;
35
+ }
36
+ resolve(out);
37
+ });
38
+ child.stdin.on("error", () => {});
39
+ child.stdin.write(stdin);
40
+ child.stdin.end();
41
+ });
42
+ var getAppleFoundationClient = () => {
43
+ return {
44
+ chat: { completions: { create: async (params) => {
45
+ const model = params.model || "system";
46
+ const instructions = params.messages.filter((m) => m.role === "system").map((m) => messageText(m.content)).join("\n\n").trim();
47
+ const prompt = params.messages.filter((m) => m.role !== "system").map((m) => messageText(m.content)).join("\n\n").trim();
48
+ const args = [
49
+ "respond",
50
+ "--no-stream",
51
+ "--model",
52
+ model
53
+ ];
54
+ if (instructions) args.push("--instructions", instructions);
55
+ return { choices: [{ message: { content: await runFm(args, prompt) } }] };
56
+ } } },
57
+ models: { list: async () => ({
58
+ data: [{
59
+ id: "system",
60
+ created: 0,
61
+ object: "model",
62
+ owned_by: "apple"
63
+ }, {
64
+ id: "pcc",
65
+ created: 0,
66
+ object: "model",
67
+ owned_by: "apple"
68
+ }],
69
+ hasNextPage: () => false,
70
+ getNextPage: async () => {
71
+ throw new Error("No more pages");
72
+ }
73
+ }) }
74
+ };
75
+ };
76
+ //#endregion
77
+ export { getAppleFoundationClient };
@@ -0,0 +1,69 @@
1
+ import { saveConfig } from "../../../config.js";
2
+ import { selectModel } from "../../setup/selectModel.js";
3
+ import { Provider } from "../base.js";
4
+ import { getAppleFoundationClient } from "./client.js";
5
+ import { CANDIDATE_MODELS, probeModel } from "./models.js";
6
+ import chalk from "chalk";
7
+ import { spawnSync } from "child_process";
8
+ import { platform } from "os";
9
+ //#region src/llm/providers/apple/index.ts
10
+ var MIN_MACOS_MAJOR = 27;
11
+ var AppleProvider = class extends Provider {
12
+ static id = "apple";
13
+ static label = "Apple Foundation Models (macOS 27+)";
14
+ static isAvailable() {
15
+ if (platform() !== "darwin") return false;
16
+ const result = spawnSync("sw_vers", ["-productVersion"], { encoding: "utf-8" });
17
+ if (result.error || !result.stdout) return false;
18
+ const major = parseInt(result.stdout.trim().split(".")[0], 10);
19
+ return Number.isFinite(major) && major >= MIN_MACOS_MAJOR;
20
+ }
21
+ static async setup(existingConfig) {
22
+ console.log(chalk.blue("Apple Foundation Models Setup"));
23
+ const probes = CANDIDATE_MODELS.map((model) => ({
24
+ model,
25
+ ...probeModel(model.id)
26
+ }));
27
+ if (probes.every((p) => p.reason === "fm-missing")) {
28
+ console.error(chalk.red("The Apple Foundation Models CLI ('fm') was not found. It ships with macOS 27 and later."));
29
+ process.exit(1);
30
+ }
31
+ const availableModels = probes.filter((p) => p.available).map((p) => p.model);
32
+ if (availableModels.length === 0) {
33
+ console.error(chalk.red("No Apple Foundation Models are available in this context. Make sure Apple Intelligence is enabled in System Settings."));
34
+ process.exit(1);
35
+ }
36
+ const notes = probes.filter((p) => !p.available).map((p) => `Note: Apple doesn't allow ${p.model.name} access from command-line tools.`);
37
+ const selectedModel = await selectModel(availableModels, existingConfig.model, notes);
38
+ const updatedConfig = {
39
+ ...existingConfig,
40
+ provider: "apple",
41
+ model: selectedModel
42
+ };
43
+ saveConfig(updatedConfig);
44
+ console.log(chalk.green(`✓ Model set to: ${chalk.yellow(selectedModel)}`));
45
+ return updatedConfig;
46
+ }
47
+ constructor(model) {
48
+ super(model || "system");
49
+ }
50
+ async getContextWindow() {
51
+ return 4096;
52
+ }
53
+ countTokens(text) {
54
+ const result = spawnSync("fm", ["token-count", "-q"], {
55
+ input: text,
56
+ encoding: "utf-8"
57
+ });
58
+ if (!result.error && result.stdout) {
59
+ const tokens = parseInt(result.stdout.replace(/[^0-9]/g, ""), 10);
60
+ if (Number.isFinite(tokens)) return tokens;
61
+ }
62
+ return super.countTokens(text);
63
+ }
64
+ getClient() {
65
+ return getAppleFoundationClient();
66
+ }
67
+ };
68
+ //#endregion
69
+ export { AppleProvider };
@@ -0,0 +1,29 @@
1
+ import { spawnSync } from "child_process";
2
+ //#region src/llm/providers/apple/models.ts
3
+ var CANDIDATE_MODELS = [{
4
+ id: "system",
5
+ name: "Apple On-Device Foundation Model",
6
+ context_length: 4096
7
+ }, {
8
+ id: "pcc",
9
+ name: "Private Cloud Compute (PCC)"
10
+ }];
11
+ var probeModel = (modelId) => {
12
+ const result = spawnSync("fm", [
13
+ "available",
14
+ "--model",
15
+ modelId
16
+ ], { encoding: "utf-8" });
17
+ if (result.error) return {
18
+ available: false,
19
+ reason: "fm-missing"
20
+ };
21
+ const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
22
+ return {
23
+ available: /available/i.test(output) && !/not available|error/i.test(output),
24
+ reason: output.trim()
25
+ };
26
+ };
27
+ var isAppleModelAvailable = (modelId) => probeModel(modelId).available;
28
+ //#endregion
29
+ export { CANDIDATE_MODELS, isAppleModelAvailable, probeModel };
@@ -0,0 +1,36 @@
1
+ //#region src/llm/providers/base.ts
2
+ var Provider = class {
3
+ model;
4
+ static requiresApiKey = false;
5
+ static requiresEndpoint = false;
6
+ static isAvailable() {
7
+ return true;
8
+ }
9
+ maxOutputTokens = 1024;
10
+ usesCompletionTokensParam = false;
11
+ constructor(model) {
12
+ this.model = model;
13
+ }
14
+ async getContextWindow() {
15
+ return Number.POSITIVE_INFINITY;
16
+ }
17
+ countTokens(text) {
18
+ return Math.ceil(text.length / 3);
19
+ }
20
+ async complete(req) {
21
+ const tokenLimit = this.usesCompletionTokensParam ? { max_completion_tokens: req.maxTokens } : { max_tokens: req.maxTokens };
22
+ return (await this.getClient().chat.completions.create({
23
+ model: this.model,
24
+ messages: [{
25
+ role: "system",
26
+ content: req.system
27
+ }, {
28
+ role: "user",
29
+ content: req.user
30
+ }],
31
+ ...tokenLimit
32
+ })).choices[0].message.content ?? "";
33
+ }
34
+ };
35
+ //#endregion
36
+ export { Provider };
@@ -0,0 +1,84 @@
1
+ import { getConfig, saveConfig } from "../../../config.js";
2
+ import { getAvailableModels } from "../../setup/getAvailableModels.js";
3
+ import { selectModel } from "../../setup/selectModel.js";
4
+ import { OpenAICompatibleProvider } from "../openaiCompatible.js";
5
+ import chalk from "chalk";
6
+ import inquirer from "inquirer";
7
+ //#region src/llm/providers/local/index.ts
8
+ var DEFAULT_CONTEXT_WINDOW = 4096;
9
+ var detectContextWindow = async (endpoint, modelId) => {
10
+ try {
11
+ const origin = new URL(endpoint).origin;
12
+ const response = await fetch(`${origin}/api/v0/models`);
13
+ if (!response.ok) return void 0;
14
+ const models = (await response.json())?.data ?? [];
15
+ const model = models.find((m) => m.id === modelId) ?? models.find((m) => m.state === "loaded");
16
+ const window = model?.loaded_context_length ?? model?.max_context_length;
17
+ return typeof window === "number" && window > 0 ? window : void 0;
18
+ } catch {
19
+ return;
20
+ }
21
+ };
22
+ var LocalProvider = class extends OpenAICompatibleProvider {
23
+ static id = "local";
24
+ static label = "Local LLM";
25
+ static requiresApiKey = false;
26
+ static requiresEndpoint = true;
27
+ static async setup(existingConfig) {
28
+ console.log(chalk.blue("Local LLM Setup"));
29
+ const endpoint = (await inquirer.prompt([{
30
+ type: "input",
31
+ name: "localLLMEndpoint",
32
+ message: "Enter local LLM API endpoint (e.g., http://127.0.0.1:1234):",
33
+ default: existingConfig.customLLMEndpoint || "http://127.0.0.1:1234",
34
+ validate: (input) => {
35
+ if (!input) return "API endpoint is required";
36
+ if (!input.startsWith("http://") && !input.startsWith("https://")) return "Must be a valid URL starting with http:// or https://";
37
+ return true;
38
+ }
39
+ }])).localLLMEndpoint;
40
+ console.log(chalk.gray("Trying to fetch available models from local LLM server..."));
41
+ const models = await getAvailableModels({ baseURLOverride: endpoint });
42
+ let selectedModel;
43
+ if (models.length > 0) {
44
+ console.log(chalk.green(`✓ Found ${models.length} models available on your local LLM server`));
45
+ selectedModel = await selectModel(models, existingConfig.model);
46
+ } else {
47
+ console.log(chalk.yellow("Could not fetch models from local LLM server, please enter model name manually"));
48
+ selectedModel = (await inquirer.prompt([{
49
+ type: "input",
50
+ name: "model",
51
+ message: "Enter model name to use with local endpoint:",
52
+ default: existingConfig.model,
53
+ validate: (input) => input ? true : "Model name is required"
54
+ }])).model;
55
+ }
56
+ const contextWindow = await detectContextWindow(endpoint, selectedModel) ?? DEFAULT_CONTEXT_WINDOW;
57
+ console.log(chalk.gray(`Using a context window of ${contextWindow} tokens.`));
58
+ const updatedConfig = {
59
+ ...existingConfig,
60
+ provider: "local",
61
+ model: selectedModel,
62
+ customLLMEndpoint: endpoint,
63
+ contextWindow
64
+ };
65
+ saveConfig(updatedConfig);
66
+ console.log(chalk.green("✓ Local LLM configuration saved"));
67
+ return updatedConfig;
68
+ }
69
+ async getContextWindow() {
70
+ const { contextWindow, customLLMEndpoint, model } = getConfig();
71
+ if (contextWindow) return contextWindow;
72
+ const detected = await detectContextWindow(customLLMEndpoint ?? "", model ?? "");
73
+ if (detected) {
74
+ saveConfig({ contextWindow: detected });
75
+ return detected;
76
+ }
77
+ return DEFAULT_CONTEXT_WINDOW;
78
+ }
79
+ baseURL() {
80
+ return getConfig().customLLMEndpoint ?? "";
81
+ }
82
+ };
83
+ //#endregion
84
+ export { LocalProvider };
@@ -0,0 +1,19 @@
1
+ import { OpenAICompatibleProvider, setupApiKeyProvider } from "../openaiCompatible.js";
2
+ //#region src/llm/providers/openai/index.ts
3
+ var OpenAIProvider = class OpenAIProvider extends OpenAICompatibleProvider {
4
+ static id = "openai";
5
+ static label = "OpenAI";
6
+ static baseURL = "https://api.openai.com/v1";
7
+ usesCompletionTokensParam = true;
8
+ static setup(existingConfig) {
9
+ return setupApiKeyProvider(existingConfig, {
10
+ baseURL: OpenAIProvider.baseURL,
11
+ label: OpenAIProvider.label
12
+ });
13
+ }
14
+ baseURL() {
15
+ return OpenAIProvider.baseURL;
16
+ }
17
+ };
18
+ //#endregion
19
+ export { OpenAIProvider };
@@ -0,0 +1,66 @@
1
+ import { saveConfig } from "../../config.js";
2
+ import { getLLMClient } from "../index.js";
3
+ import { getAvailableModels } from "../setup/getAvailableModels.js";
4
+ import { selectModel } from "../setup/selectModel.js";
5
+ import { getApiKey, promptApiKey, saveApiKey } from "./apiKey.js";
6
+ import { Provider } from "./base.js";
7
+ import chalk from "chalk";
8
+ import inquirer from "inquirer";
9
+ //#region src/llm/providers/openaiCompatible.ts
10
+ var OpenAICompatibleProvider = class extends Provider {
11
+ static requiresApiKey = true;
12
+ maxOutputTokens = 2048;
13
+ getClient() {
14
+ return getLLMClient({
15
+ baseURLOverride: this.baseURL(),
16
+ apiKey: getApiKey()
17
+ });
18
+ }
19
+ };
20
+ var setupApiKeyProvider = async (existingConfig, opts) => {
21
+ const { baseURL, label } = opts;
22
+ const listModels = opts.listModels ?? ((key) => getAvailableModels({
23
+ baseURLOverride: baseURL,
24
+ apiKey: key
25
+ }));
26
+ const providerId = existingConfig.provider ?? "";
27
+ const apiKey = await promptApiKey(existingConfig.apiKeys?.[providerId] ?? existingConfig.apiKey, label);
28
+ if (!apiKey) {
29
+ console.error(chalk.red(`API key is required for ${label}.`));
30
+ process.exit(1);
31
+ }
32
+ if (existingConfig.model) {
33
+ console.log("Current model:", chalk.yellow(existingConfig.model));
34
+ console.log("");
35
+ }
36
+ let selectedModel;
37
+ try {
38
+ console.log(chalk.gray(`Fetching available models from ${label}...`));
39
+ const models = await listModels(apiKey);
40
+ if (models.length > 0) console.log(chalk.green(`✓ Found ${models.length} models available with your API key`));
41
+ else console.log(chalk.yellow(`No models found from ${label}. Please specify a model manually.`));
42
+ selectedModel = await selectModel(models, existingConfig.model);
43
+ } catch (error) {
44
+ console.error(chalk.yellow(`Error fetching models: ${error}`));
45
+ selectedModel = (await inquirer.prompt([{
46
+ type: "input",
47
+ name: "model",
48
+ message: "Enter model identifier:",
49
+ validate: (input) => input ? true : "Model identifier is required"
50
+ }])).model;
51
+ }
52
+ saveApiKey(providerId, apiKey);
53
+ const finalConfig = {
54
+ ...existingConfig,
55
+ model: selectedModel,
56
+ apiKeys: {
57
+ ...existingConfig.apiKeys,
58
+ [providerId]: apiKey
59
+ }
60
+ };
61
+ saveConfig(finalConfig);
62
+ console.log(chalk.green(`✓ Model set to: ${chalk.yellow(selectedModel)}`));
63
+ return finalConfig;
64
+ };
65
+ //#endregion
66
+ export { OpenAICompatibleProvider, setupApiKeyProvider };
@@ -0,0 +1,19 @@
1
+ import { OPENROUTER_API_URL } from "../../index.js";
2
+ import { OpenAICompatibleProvider, setupApiKeyProvider } from "../openaiCompatible.js";
3
+ //#region src/llm/providers/openrouter/index.ts
4
+ var OpenRouterProvider = class OpenRouterProvider extends OpenAICompatibleProvider {
5
+ static id = "openrouter";
6
+ static label = "OpenRouter (remote)";
7
+ static baseURL = OPENROUTER_API_URL;
8
+ static setup(existingConfig) {
9
+ return setupApiKeyProvider(existingConfig, {
10
+ baseURL: OpenRouterProvider.baseURL,
11
+ label: OpenRouterProvider.label
12
+ });
13
+ }
14
+ baseURL() {
15
+ return OpenRouterProvider.baseURL;
16
+ }
17
+ };
18
+ //#endregion
19
+ export { OpenRouterProvider };
@@ -0,0 +1,39 @@
1
+ import { getConfig } from "../config.js";
2
+ import { getApiKey } from "./providers/apiKey.js";
3
+ import { AnthropicProvider } from "./providers/anthropic/index.js";
4
+ import { AppleProvider } from "./providers/apple/index.js";
5
+ import { LocalProvider } from "./providers/local/index.js";
6
+ import { OpenAIProvider } from "./providers/openai/index.js";
7
+ import { OpenRouterProvider } from "./providers/openrouter/index.js";
8
+ //#region src/llm/registry.ts
9
+ var PROVIDERS = [
10
+ AppleProvider,
11
+ OpenRouterProvider,
12
+ OpenAIProvider,
13
+ AnthropicProvider,
14
+ LocalProvider
15
+ ];
16
+ var getProviderClass = (id) => PROVIDERS.find((p) => p.id === id);
17
+ var getProvider = () => {
18
+ const { provider, model } = getConfig();
19
+ const ProviderImpl = getProviderClass(provider);
20
+ if (!ProviderImpl) throw new Error(`Unknown provider: ${provider ?? "(none)"}. Run "gitpt setup".`);
21
+ return new ProviderImpl(model ?? "");
22
+ };
23
+ var validateConfig = () => {
24
+ const { provider, customLLMEndpoint, model } = getConfig();
25
+ const errors = [];
26
+ const spec = getProviderClass(provider);
27
+ if (!spec) errors.push("No provider configured. Run 'gitpt setup'.");
28
+ else {
29
+ if (spec.requiresApiKey && !getApiKey()) errors.push(`API key is required for ${spec.label}.`);
30
+ if (spec.requiresEndpoint && !customLLMEndpoint) errors.push(`Custom endpoint is required for ${spec.label}.`);
31
+ }
32
+ if (!model) errors.push("Model is required.");
33
+ return {
34
+ isValid: errors.length === 0,
35
+ errors
36
+ };
37
+ };
38
+ //#endregion
39
+ export { PROVIDERS, getProvider, getProviderClass, validateConfig };
@@ -0,0 +1,17 @@
1
+ import { getLLMClient } from "../index.js";
2
+ //#region src/llm/setup/getAvailableModels.ts
3
+ var getAvailableModels = async (options) => {
4
+ const { baseURLOverride, apiKey } = options || {};
5
+ let modelsList = await getLLMClient({
6
+ baseURLOverride,
7
+ apiKey
8
+ }).models.list();
9
+ const modelsData = modelsList.data;
10
+ while (modelsList.hasNextPage()) {
11
+ modelsList = await modelsList.getNextPage();
12
+ modelsData.push(...modelsList.data);
13
+ }
14
+ return modelsData;
15
+ };
16
+ //#endregion
17
+ export { getAvailableModels };
@@ -0,0 +1,40 @@
1
+ import chalk from "chalk";
2
+ import inquirer from "inquirer";
3
+ //#region src/llm/setup/selectModel.ts
4
+ /**
5
+ * Show a list of models to select from
6
+ */
7
+ var selectModel = async (models, existingModel, notes) => {
8
+ const modelChoices = models.map((model) => ({
9
+ name: model.name ? model.context_length ? `${model.name} (Context: ${model.context_length})` : model.name : model.id,
10
+ value: model.id
11
+ }));
12
+ modelChoices.push({
13
+ name: "Other (specify model identifier)",
14
+ value: "custom"
15
+ });
16
+ const choices = [...modelChoices];
17
+ if (notes && notes.length > 0) {
18
+ choices.push(new inquirer.Separator(" "));
19
+ for (const note of notes) choices.push(new inquirer.Separator(chalk.gray(note)));
20
+ }
21
+ const answers = await inquirer.prompt([{
22
+ type: "list",
23
+ name: "modelChoice",
24
+ message: "Select an AI model:",
25
+ choices,
26
+ default: () => {
27
+ const currentIndex = modelChoices.findIndex((choice) => choice.value === existingModel);
28
+ return currentIndex >= 0 ? currentIndex : 0;
29
+ }
30
+ }, {
31
+ type: "input",
32
+ name: "customModel",
33
+ message: "Enter model identifier:",
34
+ when: (answers) => answers.modelChoice === "custom",
35
+ validate: (input) => input ? true : "Model identifier is required"
36
+ }]);
37
+ return answers.modelChoice === "custom" ? answers.customModel : answers.modelChoice;
38
+ };
39
+ //#endregion
40
+ export { selectModel };
@@ -0,0 +1,5 @@
1
+ import { getProvider } from "./registry.js";
2
+ //#region src/llm/tokenCount.ts
3
+ var countTokens = (text) => getProvider().countTokens(text);
4
+ //#endregion
5
+ export { countTokens };
@@ -0,0 +1,67 @@
1
+ var package_default = {
2
+ name: "gitpt",
3
+ version: "1.7.2",
4
+ description: "CLI tool that helps you write commit messages & pull request descriptions using AI",
5
+ main: "dist/index.js",
6
+ type: "module",
7
+ bin: { "gitpt": "dist/index.js" },
8
+ files: [
9
+ "dist/**/*",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ scripts: {
14
+ "typecheck": "tsc --noEmit",
15
+ "lint": "oxlint",
16
+ "build": "vite build",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "test:apple": "npm run build && node tests/apple-foundation-models/run.mjs",
20
+ "bench:apple": "npm run build && node tests/apple-foundation-models/benchmark.mjs",
21
+ "bench:local": "npm run build && node tests/local-model/run.mjs",
22
+ "bench:all": "npm run build && node tests/run-all.mjs",
23
+ "check:prompt": "npm run build && node tests/snapshots/check.mjs",
24
+ "build:demo": "node scripts/build-demo.mjs",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ repository: {
28
+ "type": "git",
29
+ "url": "git+https://github.com/bartaxyz/GitPT.git"
30
+ },
31
+ keywords: [
32
+ "git",
33
+ "ai",
34
+ "prompt"
35
+ ],
36
+ author: "@bartaxyz",
37
+ license: "MIT",
38
+ bugs: { "url": "https://github.com/bartaxyz/GitPT/issues" },
39
+ homepage: "https://github.com/bartaxyz/GitPT#readme",
40
+ devDependencies: {
41
+ "@types/configstore": "^6.0.2",
42
+ "@types/inquirer": "^9.0.7",
43
+ "@types/node": "^22.14.1",
44
+ "@types/node-fetch": "^2.6.12",
45
+ "ffmpeg-static": "^5.3.0",
46
+ "oxlint": "^1.71.0",
47
+ "pngjs": "^7.0.0",
48
+ "tsc-alias": "^1.8.16",
49
+ "typescript": "^5.8.3",
50
+ "vite": "^8.1.0",
51
+ "vitest": "^4.1.9"
52
+ },
53
+ dependencies: {
54
+ "@commitlint/cli": "^19.8.1",
55
+ "@commitlint/config-conventional": "^19.8.1",
56
+ "@commitlint/load": "^19.8.1",
57
+ "chalk": "^5.4.1",
58
+ "commander": "^13.1.0",
59
+ "configstore": "^7.0.0",
60
+ "inquirer": "^12.5.2",
61
+ "node-fetch": "^3.3.2",
62
+ "openai": "^4.100.0",
63
+ "ora": "^8.2.0"
64
+ }
65
+ };
66
+ //#endregion
67
+ export { package_default as default };