@gitlab/gitlab-ai-provider 3.1.0 → 3.1.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.
- package/CHANGELOG.md +8 -0
- package/README.md +49 -30
- package/dist/gitlab-gitlab-ai-provider-3.1.2.tgz +0 -0
- package/dist/index.d.mts +138 -86
- package/dist/index.d.ts +138 -86
- package/dist/index.js +74 -1225
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +69 -1219
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/gitlab-gitlab-ai-provider-3.1.0.tgz +0 -0
package/dist/index.mjs
CHANGED
|
@@ -45,14 +45,17 @@ var directAccessTokenSchema = z.object({
|
|
|
45
45
|
headers: z.record(z.string()),
|
|
46
46
|
token: z.string()
|
|
47
47
|
});
|
|
48
|
+
var DEFAULT_AI_GATEWAY_URL = "https://cloud.gitlab.com";
|
|
48
49
|
var GitLabDirectAccessClient = class {
|
|
49
50
|
config;
|
|
50
51
|
fetchFn;
|
|
52
|
+
aiGatewayUrl;
|
|
51
53
|
cachedToken = null;
|
|
52
54
|
tokenExpiresAt = 0;
|
|
53
55
|
constructor(config) {
|
|
54
56
|
this.config = config;
|
|
55
57
|
this.fetchFn = config.fetch ?? fetch;
|
|
58
|
+
this.aiGatewayUrl = config.aiGatewayUrl || process.env["GITLAB_AI_GATEWAY_URL"] || DEFAULT_AI_GATEWAY_URL;
|
|
56
59
|
}
|
|
57
60
|
/**
|
|
58
61
|
* Get a direct access token for the Anthropic proxy.
|
|
@@ -89,12 +92,23 @@ var GitLabDirectAccessClient = class {
|
|
|
89
92
|
return await this.getDirectAccessToken(true);
|
|
90
93
|
} catch (refreshError) {
|
|
91
94
|
throw new GitLabError({
|
|
92
|
-
message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}
|
|
95
|
+
message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,
|
|
96
|
+
statusCode: response.status,
|
|
97
|
+
responseBody: errorText
|
|
93
98
|
});
|
|
94
99
|
}
|
|
95
100
|
}
|
|
101
|
+
if (response.status === 403) {
|
|
102
|
+
throw new GitLabError({
|
|
103
|
+
message: `Access denied to GitLab AI features (${this.config.instanceUrl}). This may indicate that: (1) GitLab Duo is not enabled on this instance, (2) Your account does not have access to AI features, or (3) The third-party agents feature is not available. Original error: ${response.status} ${response.statusText} - ${errorText}`,
|
|
104
|
+
statusCode: response.status,
|
|
105
|
+
responseBody: errorText
|
|
106
|
+
});
|
|
107
|
+
}
|
|
96
108
|
throw new GitLabError({
|
|
97
|
-
message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}
|
|
109
|
+
message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,
|
|
110
|
+
statusCode: response.status,
|
|
111
|
+
responseBody: errorText
|
|
98
112
|
});
|
|
99
113
|
}
|
|
100
114
|
const data = await response.json();
|
|
@@ -116,7 +130,8 @@ var GitLabDirectAccessClient = class {
|
|
|
116
130
|
* Get the Anthropic proxy base URL
|
|
117
131
|
*/
|
|
118
132
|
getAnthropicProxyUrl() {
|
|
119
|
-
|
|
133
|
+
const baseUrl = this.aiGatewayUrl.replace(/\/$/, "");
|
|
134
|
+
return `${baseUrl}/ai/v1/proxy/anthropic/`;
|
|
120
135
|
}
|
|
121
136
|
/**
|
|
122
137
|
* Invalidate the cached token
|
|
@@ -128,6 +143,8 @@ var GitLabDirectAccessClient = class {
|
|
|
128
143
|
};
|
|
129
144
|
|
|
130
145
|
// src/gitlab-agentic-language-model.ts
|
|
146
|
+
var debugLog = (..._args) => {
|
|
147
|
+
};
|
|
131
148
|
var GitLabAgenticLanguageModel = class {
|
|
132
149
|
specificationVersion = "v2";
|
|
133
150
|
modelId;
|
|
@@ -143,7 +160,8 @@ var GitLabAgenticLanguageModel = class {
|
|
|
143
160
|
getHeaders: config.getHeaders,
|
|
144
161
|
refreshApiKey: config.refreshApiKey,
|
|
145
162
|
fetch: config.fetch,
|
|
146
|
-
featureFlags: config.featureFlags
|
|
163
|
+
featureFlags: config.featureFlags,
|
|
164
|
+
aiGatewayUrl: config.aiGatewayUrl
|
|
147
165
|
});
|
|
148
166
|
}
|
|
149
167
|
get provider() {
|
|
@@ -155,10 +173,19 @@ var GitLabAgenticLanguageModel = class {
|
|
|
155
173
|
*/
|
|
156
174
|
async getAnthropicClient(forceRefresh = false) {
|
|
157
175
|
const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);
|
|
176
|
+
debugLog("[gitlab-ai-provider] Token headers from GitLab:", tokenData.headers);
|
|
177
|
+
debugLog("[gitlab-ai-provider] Proxy URL:", this.directAccessClient.getAnthropicProxyUrl());
|
|
178
|
+
const { "x-api-key": _removed, ...filteredHeaders } = tokenData.headers;
|
|
179
|
+
if (_removed) {
|
|
180
|
+
debugLog(
|
|
181
|
+
"[gitlab-ai-provider] Filtered out x-api-key from headers (using authToken instead)"
|
|
182
|
+
);
|
|
183
|
+
}
|
|
158
184
|
this.anthropicClient = new Anthropic({
|
|
185
|
+
apiKey: null,
|
|
159
186
|
authToken: tokenData.token,
|
|
160
187
|
baseURL: this.directAccessClient.getAnthropicProxyUrl(),
|
|
161
|
-
defaultHeaders:
|
|
188
|
+
defaultHeaders: filteredHeaders
|
|
162
189
|
});
|
|
163
190
|
return this.anthropicClient;
|
|
164
191
|
}
|
|
@@ -699,6 +726,16 @@ var GitLabOAuthManager = class {
|
|
|
699
726
|
}
|
|
700
727
|
};
|
|
701
728
|
|
|
729
|
+
// src/model-mappings.ts
|
|
730
|
+
var MODEL_ID_TO_ANTHROPIC_MODEL = {
|
|
731
|
+
"duo-chat-opus-4-5": "claude-opus-4-5-20251101",
|
|
732
|
+
"duo-chat-sonnet-4-5": "claude-sonnet-4-5-20250929",
|
|
733
|
+
"duo-chat-haiku-4-5": "claude-haiku-4-5-20251001"
|
|
734
|
+
};
|
|
735
|
+
function getAnthropicModelForModelId(modelId) {
|
|
736
|
+
return MODEL_ID_TO_ANTHROPIC_MODEL[modelId];
|
|
737
|
+
}
|
|
738
|
+
|
|
702
739
|
// src/gitlab-provider.ts
|
|
703
740
|
import * as fs from "fs";
|
|
704
741
|
import * as path from "path";
|
|
@@ -845,9 +882,10 @@ function createGitLab(options = {}) {
|
|
|
845
882
|
getHeaders,
|
|
846
883
|
refreshApiKey,
|
|
847
884
|
fetch: options.fetch,
|
|
848
|
-
anthropicModel: agenticOptions?.anthropicModel,
|
|
885
|
+
anthropicModel: agenticOptions?.anthropicModel ?? getAnthropicModelForModelId(modelId),
|
|
849
886
|
maxTokens: agenticOptions?.maxTokens,
|
|
850
|
-
featureFlags
|
|
887
|
+
featureFlags,
|
|
888
|
+
aiGatewayUrl: options.aiGatewayUrl
|
|
851
889
|
});
|
|
852
890
|
};
|
|
853
891
|
const createDefaultModel = (modelId) => {
|
|
@@ -873,1196 +911,9 @@ function createGitLab(options = {}) {
|
|
|
873
911
|
}
|
|
874
912
|
var gitlab = createGitLab();
|
|
875
913
|
|
|
876
|
-
// src/gitlab-api-tools.ts
|
|
877
|
-
var GITLAB_API_TOOLS = [
|
|
878
|
-
// Merge Request Tools
|
|
879
|
-
{
|
|
880
|
-
name: "gitlab_get_merge_request",
|
|
881
|
-
description: `Get details of a specific merge request by project and MR IID.
|
|
882
|
-
Returns: title, description, state, author, assignees, reviewers, labels, diff stats, and discussion notes.`,
|
|
883
|
-
input_schema: {
|
|
884
|
-
type: "object",
|
|
885
|
-
properties: {
|
|
886
|
-
project_id: {
|
|
887
|
-
type: "string",
|
|
888
|
-
description: 'The project ID or URL-encoded path (e.g., "gitlab-org/gitlab" or "123")'
|
|
889
|
-
},
|
|
890
|
-
mr_iid: {
|
|
891
|
-
type: "number",
|
|
892
|
-
description: "The internal ID of the merge request within the project"
|
|
893
|
-
},
|
|
894
|
-
include_changes: {
|
|
895
|
-
type: "boolean",
|
|
896
|
-
description: "Whether to include the list of changed files (default: false)"
|
|
897
|
-
}
|
|
898
|
-
},
|
|
899
|
-
required: ["project_id", "mr_iid"]
|
|
900
|
-
}
|
|
901
|
-
},
|
|
902
|
-
{
|
|
903
|
-
name: "gitlab_list_merge_requests",
|
|
904
|
-
description: `List merge requests for a project or search globally.
|
|
905
|
-
Can filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels.`,
|
|
906
|
-
input_schema: {
|
|
907
|
-
type: "object",
|
|
908
|
-
properties: {
|
|
909
|
-
project_id: {
|
|
910
|
-
type: "string",
|
|
911
|
-
description: "The project ID or path. If not provided, searches globally."
|
|
912
|
-
},
|
|
913
|
-
state: {
|
|
914
|
-
type: "string",
|
|
915
|
-
enum: ["opened", "closed", "merged", "all"],
|
|
916
|
-
description: "Filter by MR state (default: opened)"
|
|
917
|
-
},
|
|
918
|
-
scope: {
|
|
919
|
-
type: "string",
|
|
920
|
-
enum: ["assigned_to_me", "created_by_me", "all"],
|
|
921
|
-
description: "Filter by scope"
|
|
922
|
-
},
|
|
923
|
-
search: {
|
|
924
|
-
type: "string",
|
|
925
|
-
description: "Search MRs by title or description"
|
|
926
|
-
},
|
|
927
|
-
labels: {
|
|
928
|
-
type: "string",
|
|
929
|
-
description: "Comma-separated list of labels to filter by"
|
|
930
|
-
},
|
|
931
|
-
limit: {
|
|
932
|
-
type: "number",
|
|
933
|
-
description: "Maximum number of results (default: 20)"
|
|
934
|
-
}
|
|
935
|
-
},
|
|
936
|
-
required: []
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
{
|
|
940
|
-
name: "gitlab_get_mr_changes",
|
|
941
|
-
description: `Get the file changes (diff) for a merge request.
|
|
942
|
-
Returns the list of files changed with their diffs.`,
|
|
943
|
-
input_schema: {
|
|
944
|
-
type: "object",
|
|
945
|
-
properties: {
|
|
946
|
-
project_id: {
|
|
947
|
-
type: "string",
|
|
948
|
-
description: "The project ID or URL-encoded path"
|
|
949
|
-
},
|
|
950
|
-
mr_iid: {
|
|
951
|
-
type: "number",
|
|
952
|
-
description: "The internal ID of the merge request"
|
|
953
|
-
}
|
|
954
|
-
},
|
|
955
|
-
required: ["project_id", "mr_iid"]
|
|
956
|
-
}
|
|
957
|
-
},
|
|
958
|
-
{
|
|
959
|
-
name: "gitlab_list_mr_discussions",
|
|
960
|
-
description: `List discussions (comments/threads) on a merge request.
|
|
961
|
-
Returns all discussion threads including resolved status.`,
|
|
962
|
-
input_schema: {
|
|
963
|
-
type: "object",
|
|
964
|
-
properties: {
|
|
965
|
-
project_id: {
|
|
966
|
-
type: "string",
|
|
967
|
-
description: "The project ID or URL-encoded path"
|
|
968
|
-
},
|
|
969
|
-
mr_iid: {
|
|
970
|
-
type: "number",
|
|
971
|
-
description: "The internal ID of the merge request"
|
|
972
|
-
}
|
|
973
|
-
},
|
|
974
|
-
required: ["project_id", "mr_iid"]
|
|
975
|
-
}
|
|
976
|
-
},
|
|
977
|
-
{
|
|
978
|
-
name: "gitlab_create_mr_note",
|
|
979
|
-
description: `Add a comment/note to a merge request.`,
|
|
980
|
-
input_schema: {
|
|
981
|
-
type: "object",
|
|
982
|
-
properties: {
|
|
983
|
-
project_id: {
|
|
984
|
-
type: "string",
|
|
985
|
-
description: "The project ID or URL-encoded path"
|
|
986
|
-
},
|
|
987
|
-
mr_iid: {
|
|
988
|
-
type: "number",
|
|
989
|
-
description: "The internal ID of the merge request"
|
|
990
|
-
},
|
|
991
|
-
body: {
|
|
992
|
-
type: "string",
|
|
993
|
-
description: "The content of the note/comment (supports Markdown)"
|
|
994
|
-
}
|
|
995
|
-
},
|
|
996
|
-
required: ["project_id", "mr_iid", "body"]
|
|
997
|
-
}
|
|
998
|
-
},
|
|
999
|
-
// Issue Tools
|
|
1000
|
-
{
|
|
1001
|
-
name: "gitlab_get_issue",
|
|
1002
|
-
description: `Get details of a specific issue by project and issue IID.
|
|
1003
|
-
Returns: title, description, state, author, assignees, labels, milestone, weight, and comments.`,
|
|
1004
|
-
input_schema: {
|
|
1005
|
-
type: "object",
|
|
1006
|
-
properties: {
|
|
1007
|
-
project_id: {
|
|
1008
|
-
type: "string",
|
|
1009
|
-
description: "The project ID or URL-encoded path"
|
|
1010
|
-
},
|
|
1011
|
-
issue_iid: {
|
|
1012
|
-
type: "number",
|
|
1013
|
-
description: "The internal ID of the issue within the project"
|
|
1014
|
-
}
|
|
1015
|
-
},
|
|
1016
|
-
required: ["project_id", "issue_iid"]
|
|
1017
|
-
}
|
|
1018
|
-
},
|
|
1019
|
-
{
|
|
1020
|
-
name: "gitlab_list_issues",
|
|
1021
|
-
description: `List issues for a project or search globally.
|
|
1022
|
-
Can filter by state, labels, assignee, milestone.`,
|
|
1023
|
-
input_schema: {
|
|
1024
|
-
type: "object",
|
|
1025
|
-
properties: {
|
|
1026
|
-
project_id: {
|
|
1027
|
-
type: "string",
|
|
1028
|
-
description: "The project ID or path. If not provided, searches globally."
|
|
1029
|
-
},
|
|
1030
|
-
state: {
|
|
1031
|
-
type: "string",
|
|
1032
|
-
enum: ["opened", "closed", "all"],
|
|
1033
|
-
description: "Filter by issue state (default: opened)"
|
|
1034
|
-
},
|
|
1035
|
-
scope: {
|
|
1036
|
-
type: "string",
|
|
1037
|
-
enum: ["assigned_to_me", "created_by_me", "all"],
|
|
1038
|
-
description: "Filter by scope"
|
|
1039
|
-
},
|
|
1040
|
-
search: {
|
|
1041
|
-
type: "string",
|
|
1042
|
-
description: "Search issues by title or description"
|
|
1043
|
-
},
|
|
1044
|
-
labels: {
|
|
1045
|
-
type: "string",
|
|
1046
|
-
description: "Comma-separated list of labels to filter by"
|
|
1047
|
-
},
|
|
1048
|
-
milestone: {
|
|
1049
|
-
type: "string",
|
|
1050
|
-
description: "Filter by milestone title"
|
|
1051
|
-
},
|
|
1052
|
-
limit: {
|
|
1053
|
-
type: "number",
|
|
1054
|
-
description: "Maximum number of results (default: 20)"
|
|
1055
|
-
}
|
|
1056
|
-
},
|
|
1057
|
-
required: []
|
|
1058
|
-
}
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
name: "gitlab_create_issue_note",
|
|
1062
|
-
description: `Add a comment/note to an issue.`,
|
|
1063
|
-
input_schema: {
|
|
1064
|
-
type: "object",
|
|
1065
|
-
properties: {
|
|
1066
|
-
project_id: {
|
|
1067
|
-
type: "string",
|
|
1068
|
-
description: "The project ID or URL-encoded path"
|
|
1069
|
-
},
|
|
1070
|
-
issue_iid: {
|
|
1071
|
-
type: "number",
|
|
1072
|
-
description: "The internal ID of the issue"
|
|
1073
|
-
},
|
|
1074
|
-
body: {
|
|
1075
|
-
type: "string",
|
|
1076
|
-
description: "The content of the note/comment (supports Markdown)"
|
|
1077
|
-
}
|
|
1078
|
-
},
|
|
1079
|
-
required: ["project_id", "issue_iid", "body"]
|
|
1080
|
-
}
|
|
1081
|
-
},
|
|
1082
|
-
// Pipeline/CI Tools
|
|
1083
|
-
{
|
|
1084
|
-
name: "gitlab_list_pipelines",
|
|
1085
|
-
description: `List pipelines for a project.
|
|
1086
|
-
Can filter by status, ref (branch/tag), username.`,
|
|
1087
|
-
input_schema: {
|
|
1088
|
-
type: "object",
|
|
1089
|
-
properties: {
|
|
1090
|
-
project_id: {
|
|
1091
|
-
type: "string",
|
|
1092
|
-
description: "The project ID or URL-encoded path"
|
|
1093
|
-
},
|
|
1094
|
-
status: {
|
|
1095
|
-
type: "string",
|
|
1096
|
-
enum: ["running", "pending", "success", "failed", "canceled", "skipped", "manual"],
|
|
1097
|
-
description: "Filter by pipeline status"
|
|
1098
|
-
},
|
|
1099
|
-
ref: {
|
|
1100
|
-
type: "string",
|
|
1101
|
-
description: "Filter by branch or tag name"
|
|
1102
|
-
},
|
|
1103
|
-
limit: {
|
|
1104
|
-
type: "number",
|
|
1105
|
-
description: "Maximum number of results (default: 20)"
|
|
1106
|
-
}
|
|
1107
|
-
},
|
|
1108
|
-
required: ["project_id"]
|
|
1109
|
-
}
|
|
1110
|
-
},
|
|
1111
|
-
{
|
|
1112
|
-
name: "gitlab_get_pipeline",
|
|
1113
|
-
description: `Get details of a specific pipeline including its jobs.`,
|
|
1114
|
-
input_schema: {
|
|
1115
|
-
type: "object",
|
|
1116
|
-
properties: {
|
|
1117
|
-
project_id: {
|
|
1118
|
-
type: "string",
|
|
1119
|
-
description: "The project ID or URL-encoded path"
|
|
1120
|
-
},
|
|
1121
|
-
pipeline_id: {
|
|
1122
|
-
type: "number",
|
|
1123
|
-
description: "The ID of the pipeline"
|
|
1124
|
-
}
|
|
1125
|
-
},
|
|
1126
|
-
required: ["project_id", "pipeline_id"]
|
|
1127
|
-
}
|
|
1128
|
-
},
|
|
1129
|
-
{
|
|
1130
|
-
name: "gitlab_list_pipeline_jobs",
|
|
1131
|
-
description: `List jobs for a pipeline, optionally filter by scope (failed, success, etc).`,
|
|
1132
|
-
input_schema: {
|
|
1133
|
-
type: "object",
|
|
1134
|
-
properties: {
|
|
1135
|
-
project_id: {
|
|
1136
|
-
type: "string",
|
|
1137
|
-
description: "The project ID or URL-encoded path"
|
|
1138
|
-
},
|
|
1139
|
-
pipeline_id: {
|
|
1140
|
-
type: "number",
|
|
1141
|
-
description: "The ID of the pipeline"
|
|
1142
|
-
},
|
|
1143
|
-
scope: {
|
|
1144
|
-
type: "string",
|
|
1145
|
-
enum: [
|
|
1146
|
-
"created",
|
|
1147
|
-
"pending",
|
|
1148
|
-
"running",
|
|
1149
|
-
"failed",
|
|
1150
|
-
"success",
|
|
1151
|
-
"canceled",
|
|
1152
|
-
"skipped",
|
|
1153
|
-
"manual"
|
|
1154
|
-
],
|
|
1155
|
-
description: "Filter jobs by scope/status"
|
|
1156
|
-
}
|
|
1157
|
-
},
|
|
1158
|
-
required: ["project_id", "pipeline_id"]
|
|
1159
|
-
}
|
|
1160
|
-
},
|
|
1161
|
-
{
|
|
1162
|
-
name: "gitlab_get_job_log",
|
|
1163
|
-
description: `Get the log/trace output of a specific CI job.`,
|
|
1164
|
-
input_schema: {
|
|
1165
|
-
type: "object",
|
|
1166
|
-
properties: {
|
|
1167
|
-
project_id: {
|
|
1168
|
-
type: "string",
|
|
1169
|
-
description: "The project ID or URL-encoded path"
|
|
1170
|
-
},
|
|
1171
|
-
job_id: {
|
|
1172
|
-
type: "number",
|
|
1173
|
-
description: "The ID of the job"
|
|
1174
|
-
}
|
|
1175
|
-
},
|
|
1176
|
-
required: ["project_id", "job_id"]
|
|
1177
|
-
}
|
|
1178
|
-
},
|
|
1179
|
-
{
|
|
1180
|
-
name: "gitlab_retry_job",
|
|
1181
|
-
description: `Retry a failed or canceled CI job.`,
|
|
1182
|
-
input_schema: {
|
|
1183
|
-
type: "object",
|
|
1184
|
-
properties: {
|
|
1185
|
-
project_id: {
|
|
1186
|
-
type: "string",
|
|
1187
|
-
description: "The project ID or URL-encoded path"
|
|
1188
|
-
},
|
|
1189
|
-
job_id: {
|
|
1190
|
-
type: "number",
|
|
1191
|
-
description: "The ID of the job to retry"
|
|
1192
|
-
}
|
|
1193
|
-
},
|
|
1194
|
-
required: ["project_id", "job_id"]
|
|
1195
|
-
}
|
|
1196
|
-
},
|
|
1197
|
-
// Repository Tools
|
|
1198
|
-
{
|
|
1199
|
-
name: "gitlab_get_file",
|
|
1200
|
-
description: `Get the contents of a file from a repository.`,
|
|
1201
|
-
input_schema: {
|
|
1202
|
-
type: "object",
|
|
1203
|
-
properties: {
|
|
1204
|
-
project_id: {
|
|
1205
|
-
type: "string",
|
|
1206
|
-
description: "The project ID or URL-encoded path"
|
|
1207
|
-
},
|
|
1208
|
-
file_path: {
|
|
1209
|
-
type: "string",
|
|
1210
|
-
description: "Path to the file in the repository"
|
|
1211
|
-
},
|
|
1212
|
-
ref: {
|
|
1213
|
-
type: "string",
|
|
1214
|
-
description: "Branch, tag, or commit SHA (default: default branch)"
|
|
1215
|
-
}
|
|
1216
|
-
},
|
|
1217
|
-
required: ["project_id", "file_path"]
|
|
1218
|
-
}
|
|
1219
|
-
},
|
|
1220
|
-
{
|
|
1221
|
-
name: "gitlab_list_commits",
|
|
1222
|
-
description: `List commits in a repository. Can filter by branch/ref and path.`,
|
|
1223
|
-
input_schema: {
|
|
1224
|
-
type: "object",
|
|
1225
|
-
properties: {
|
|
1226
|
-
project_id: {
|
|
1227
|
-
type: "string",
|
|
1228
|
-
description: "The project ID or URL-encoded path"
|
|
1229
|
-
},
|
|
1230
|
-
ref: {
|
|
1231
|
-
type: "string",
|
|
1232
|
-
description: "Branch or tag name"
|
|
1233
|
-
},
|
|
1234
|
-
path: {
|
|
1235
|
-
type: "string",
|
|
1236
|
-
description: "File or directory path to filter commits"
|
|
1237
|
-
},
|
|
1238
|
-
since: {
|
|
1239
|
-
type: "string",
|
|
1240
|
-
description: "Only commits after this date (ISO 8601 format)"
|
|
1241
|
-
},
|
|
1242
|
-
until: {
|
|
1243
|
-
type: "string",
|
|
1244
|
-
description: "Only commits before this date (ISO 8601 format)"
|
|
1245
|
-
},
|
|
1246
|
-
limit: {
|
|
1247
|
-
type: "number",
|
|
1248
|
-
description: "Maximum number of results (default: 20)"
|
|
1249
|
-
}
|
|
1250
|
-
},
|
|
1251
|
-
required: ["project_id"]
|
|
1252
|
-
}
|
|
1253
|
-
},
|
|
1254
|
-
{
|
|
1255
|
-
name: "gitlab_get_commit_diff",
|
|
1256
|
-
description: `Get the diff for a specific commit.`,
|
|
1257
|
-
input_schema: {
|
|
1258
|
-
type: "object",
|
|
1259
|
-
properties: {
|
|
1260
|
-
project_id: {
|
|
1261
|
-
type: "string",
|
|
1262
|
-
description: "The project ID or URL-encoded path"
|
|
1263
|
-
},
|
|
1264
|
-
sha: {
|
|
1265
|
-
type: "string",
|
|
1266
|
-
description: "The commit SHA"
|
|
1267
|
-
}
|
|
1268
|
-
},
|
|
1269
|
-
required: ["project_id", "sha"]
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
{
|
|
1273
|
-
name: "gitlab_list_branches",
|
|
1274
|
-
description: `List branches in a repository.`,
|
|
1275
|
-
input_schema: {
|
|
1276
|
-
type: "object",
|
|
1277
|
-
properties: {
|
|
1278
|
-
project_id: {
|
|
1279
|
-
type: "string",
|
|
1280
|
-
description: "The project ID or URL-encoded path"
|
|
1281
|
-
},
|
|
1282
|
-
search: {
|
|
1283
|
-
type: "string",
|
|
1284
|
-
description: "Search branches by name"
|
|
1285
|
-
}
|
|
1286
|
-
},
|
|
1287
|
-
required: ["project_id"]
|
|
1288
|
-
}
|
|
1289
|
-
},
|
|
1290
|
-
// Search Tools
|
|
1291
|
-
{
|
|
1292
|
-
name: "gitlab_search",
|
|
1293
|
-
description: `Search across GitLab for various resources.
|
|
1294
|
-
Scopes: projects, issues, merge_requests, milestones, users, blobs (code), commits, notes, wiki_blobs`,
|
|
1295
|
-
input_schema: {
|
|
1296
|
-
type: "object",
|
|
1297
|
-
properties: {
|
|
1298
|
-
scope: {
|
|
1299
|
-
type: "string",
|
|
1300
|
-
enum: [
|
|
1301
|
-
"projects",
|
|
1302
|
-
"issues",
|
|
1303
|
-
"merge_requests",
|
|
1304
|
-
"milestones",
|
|
1305
|
-
"users",
|
|
1306
|
-
"blobs",
|
|
1307
|
-
"commits",
|
|
1308
|
-
"notes",
|
|
1309
|
-
"wiki_blobs"
|
|
1310
|
-
],
|
|
1311
|
-
description: "The scope of the search"
|
|
1312
|
-
},
|
|
1313
|
-
search: {
|
|
1314
|
-
type: "string",
|
|
1315
|
-
description: "The search query"
|
|
1316
|
-
},
|
|
1317
|
-
project_id: {
|
|
1318
|
-
type: "string",
|
|
1319
|
-
description: "Limit search to a specific project (optional)"
|
|
1320
|
-
},
|
|
1321
|
-
limit: {
|
|
1322
|
-
type: "number",
|
|
1323
|
-
description: "Maximum number of results (default: 20)"
|
|
1324
|
-
}
|
|
1325
|
-
},
|
|
1326
|
-
required: ["scope", "search"]
|
|
1327
|
-
}
|
|
1328
|
-
},
|
|
1329
|
-
// Project Tools
|
|
1330
|
-
{
|
|
1331
|
-
name: "gitlab_get_project",
|
|
1332
|
-
description: `Get details of a specific project.`,
|
|
1333
|
-
input_schema: {
|
|
1334
|
-
type: "object",
|
|
1335
|
-
properties: {
|
|
1336
|
-
project_id: {
|
|
1337
|
-
type: "string",
|
|
1338
|
-
description: 'The project ID or URL-encoded path (e.g., "gitlab-org/gitlab")'
|
|
1339
|
-
}
|
|
1340
|
-
},
|
|
1341
|
-
required: ["project_id"]
|
|
1342
|
-
}
|
|
1343
|
-
},
|
|
1344
|
-
{
|
|
1345
|
-
name: "gitlab_list_project_members",
|
|
1346
|
-
description: `List members of a project.`,
|
|
1347
|
-
input_schema: {
|
|
1348
|
-
type: "object",
|
|
1349
|
-
properties: {
|
|
1350
|
-
project_id: {
|
|
1351
|
-
type: "string",
|
|
1352
|
-
description: "The project ID or URL-encoded path"
|
|
1353
|
-
}
|
|
1354
|
-
},
|
|
1355
|
-
required: ["project_id"]
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
];
|
|
1359
|
-
var GitLabApiToolExecutor = class {
|
|
1360
|
-
config;
|
|
1361
|
-
constructor(config) {
|
|
1362
|
-
this.config = config;
|
|
1363
|
-
}
|
|
1364
|
-
get headers() {
|
|
1365
|
-
return {
|
|
1366
|
-
Authorization: `Bearer ${this.config.token}`,
|
|
1367
|
-
"Content-Type": "application/json"
|
|
1368
|
-
};
|
|
1369
|
-
}
|
|
1370
|
-
async fetchApi(method, path4, body) {
|
|
1371
|
-
const url = `${this.config.instanceUrl}/api/v4${path4}`;
|
|
1372
|
-
const fetchFn = this.config.fetch || fetch;
|
|
1373
|
-
const response = await fetchFn(url, {
|
|
1374
|
-
method,
|
|
1375
|
-
headers: this.headers,
|
|
1376
|
-
body: body ? JSON.stringify(body) : void 0
|
|
1377
|
-
});
|
|
1378
|
-
if (!response.ok) {
|
|
1379
|
-
const errorText = await response.text();
|
|
1380
|
-
throw new Error(`GitLab API error ${response.status}: ${errorText}`);
|
|
1381
|
-
}
|
|
1382
|
-
const text = await response.text();
|
|
1383
|
-
if (!text) {
|
|
1384
|
-
return {};
|
|
1385
|
-
}
|
|
1386
|
-
return JSON.parse(text);
|
|
1387
|
-
}
|
|
1388
|
-
encodeProjectId(projectId) {
|
|
1389
|
-
if (projectId.includes("/")) {
|
|
1390
|
-
return encodeURIComponent(projectId);
|
|
1391
|
-
}
|
|
1392
|
-
return projectId;
|
|
1393
|
-
}
|
|
1394
|
-
/**
|
|
1395
|
-
* Execute a GitLab API tool by name
|
|
1396
|
-
*/
|
|
1397
|
-
async execute(toolName, input) {
|
|
1398
|
-
try {
|
|
1399
|
-
switch (toolName) {
|
|
1400
|
-
// Merge Request tools
|
|
1401
|
-
case "gitlab_get_merge_request":
|
|
1402
|
-
return this.getMergeRequest(input);
|
|
1403
|
-
case "gitlab_list_merge_requests":
|
|
1404
|
-
return this.listMergeRequests(input);
|
|
1405
|
-
case "gitlab_get_mr_changes":
|
|
1406
|
-
return this.getMrChanges(input);
|
|
1407
|
-
case "gitlab_list_mr_discussions":
|
|
1408
|
-
return this.listMrDiscussions(input);
|
|
1409
|
-
case "gitlab_create_mr_note":
|
|
1410
|
-
return this.createMrNote(input);
|
|
1411
|
-
// Issue tools
|
|
1412
|
-
case "gitlab_get_issue":
|
|
1413
|
-
return this.getIssue(input);
|
|
1414
|
-
case "gitlab_list_issues":
|
|
1415
|
-
return this.listIssues(input);
|
|
1416
|
-
case "gitlab_create_issue_note":
|
|
1417
|
-
return this.createIssueNote(input);
|
|
1418
|
-
// Pipeline tools
|
|
1419
|
-
case "gitlab_list_pipelines":
|
|
1420
|
-
return this.listPipelines(input);
|
|
1421
|
-
case "gitlab_get_pipeline":
|
|
1422
|
-
return this.getPipeline(input);
|
|
1423
|
-
case "gitlab_list_pipeline_jobs":
|
|
1424
|
-
return this.listPipelineJobs(input);
|
|
1425
|
-
case "gitlab_get_job_log":
|
|
1426
|
-
return this.getJobLog(input);
|
|
1427
|
-
case "gitlab_retry_job":
|
|
1428
|
-
return this.retryJob(input);
|
|
1429
|
-
// Repository tools
|
|
1430
|
-
case "gitlab_get_file":
|
|
1431
|
-
return this.getFile(input);
|
|
1432
|
-
case "gitlab_list_commits":
|
|
1433
|
-
return this.listCommits(input);
|
|
1434
|
-
case "gitlab_get_commit_diff":
|
|
1435
|
-
return this.getCommitDiff(input);
|
|
1436
|
-
case "gitlab_list_branches":
|
|
1437
|
-
return this.listBranches(input);
|
|
1438
|
-
// Search tools
|
|
1439
|
-
case "gitlab_search":
|
|
1440
|
-
return this.search(input);
|
|
1441
|
-
// Project tools
|
|
1442
|
-
case "gitlab_get_project":
|
|
1443
|
-
return this.getProject(input);
|
|
1444
|
-
case "gitlab_list_project_members":
|
|
1445
|
-
return this.listProjectMembers(input);
|
|
1446
|
-
default:
|
|
1447
|
-
return { result: "", error: `Unknown GitLab tool: ${toolName}` };
|
|
1448
|
-
}
|
|
1449
|
-
} catch (error) {
|
|
1450
|
-
return {
|
|
1451
|
-
result: "",
|
|
1452
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
// ========== Merge Request Tools ==========
|
|
1457
|
-
async getMergeRequest(input) {
|
|
1458
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1459
|
-
const mrIid = input.mr_iid;
|
|
1460
|
-
const includeChanges = input.include_changes;
|
|
1461
|
-
let path4 = `/projects/${projectId}/merge_requests/${mrIid}`;
|
|
1462
|
-
if (includeChanges) {
|
|
1463
|
-
path4 += "?include_diverged_commits_count=true";
|
|
1464
|
-
}
|
|
1465
|
-
const mr = await this.fetchApi("GET", path4);
|
|
1466
|
-
return { result: JSON.stringify(mr, null, 2) };
|
|
1467
|
-
}
|
|
1468
|
-
async listMergeRequests(input) {
|
|
1469
|
-
const params = new URLSearchParams();
|
|
1470
|
-
params.set("per_page", String(input.limit || 20));
|
|
1471
|
-
if (input.state) params.set("state", input.state);
|
|
1472
|
-
if (input.scope) params.set("scope", input.scope);
|
|
1473
|
-
if (input.search) params.set("search", input.search);
|
|
1474
|
-
if (input.labels) params.set("labels", input.labels);
|
|
1475
|
-
let path4;
|
|
1476
|
-
if (input.project_id) {
|
|
1477
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1478
|
-
path4 = `/projects/${projectId}/merge_requests?${params}`;
|
|
1479
|
-
} else {
|
|
1480
|
-
path4 = `/merge_requests?${params}`;
|
|
1481
|
-
}
|
|
1482
|
-
const mrs = await this.fetchApi("GET", path4);
|
|
1483
|
-
return { result: JSON.stringify(mrs, null, 2) };
|
|
1484
|
-
}
|
|
1485
|
-
async getMrChanges(input) {
|
|
1486
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1487
|
-
const mrIid = input.mr_iid;
|
|
1488
|
-
const changes = await this.fetchApi(
|
|
1489
|
-
"GET",
|
|
1490
|
-
`/projects/${projectId}/merge_requests/${mrIid}/changes`
|
|
1491
|
-
);
|
|
1492
|
-
return { result: JSON.stringify(changes, null, 2) };
|
|
1493
|
-
}
|
|
1494
|
-
async listMrDiscussions(input) {
|
|
1495
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1496
|
-
const mrIid = input.mr_iid;
|
|
1497
|
-
const discussions = await this.fetchApi(
|
|
1498
|
-
"GET",
|
|
1499
|
-
`/projects/${projectId}/merge_requests/${mrIid}/discussions`
|
|
1500
|
-
);
|
|
1501
|
-
return { result: JSON.stringify(discussions, null, 2) };
|
|
1502
|
-
}
|
|
1503
|
-
async createMrNote(input) {
|
|
1504
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1505
|
-
const mrIid = input.mr_iid;
|
|
1506
|
-
const body = input.body;
|
|
1507
|
-
const note = await this.fetchApi(
|
|
1508
|
-
"POST",
|
|
1509
|
-
`/projects/${projectId}/merge_requests/${mrIid}/notes`,
|
|
1510
|
-
{ body }
|
|
1511
|
-
);
|
|
1512
|
-
return { result: JSON.stringify(note, null, 2) };
|
|
1513
|
-
}
|
|
1514
|
-
// ========== Issue Tools ==========
|
|
1515
|
-
async getIssue(input) {
|
|
1516
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1517
|
-
const issueIid = input.issue_iid;
|
|
1518
|
-
const issue = await this.fetchApi(
|
|
1519
|
-
"GET",
|
|
1520
|
-
`/projects/${projectId}/issues/${issueIid}`
|
|
1521
|
-
);
|
|
1522
|
-
return { result: JSON.stringify(issue, null, 2) };
|
|
1523
|
-
}
|
|
1524
|
-
async listIssues(input) {
|
|
1525
|
-
const params = new URLSearchParams();
|
|
1526
|
-
params.set("per_page", String(input.limit || 20));
|
|
1527
|
-
if (input.state) params.set("state", input.state);
|
|
1528
|
-
if (input.scope) params.set("scope", input.scope);
|
|
1529
|
-
if (input.search) params.set("search", input.search);
|
|
1530
|
-
if (input.labels) params.set("labels", input.labels);
|
|
1531
|
-
if (input.milestone) params.set("milestone", input.milestone);
|
|
1532
|
-
let path4;
|
|
1533
|
-
if (input.project_id) {
|
|
1534
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1535
|
-
path4 = `/projects/${projectId}/issues?${params}`;
|
|
1536
|
-
} else {
|
|
1537
|
-
path4 = `/issues?${params}`;
|
|
1538
|
-
}
|
|
1539
|
-
const issues = await this.fetchApi("GET", path4);
|
|
1540
|
-
return { result: JSON.stringify(issues, null, 2) };
|
|
1541
|
-
}
|
|
1542
|
-
async createIssueNote(input) {
|
|
1543
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1544
|
-
const issueIid = input.issue_iid;
|
|
1545
|
-
const body = input.body;
|
|
1546
|
-
const note = await this.fetchApi(
|
|
1547
|
-
"POST",
|
|
1548
|
-
`/projects/${projectId}/issues/${issueIid}/notes`,
|
|
1549
|
-
{ body }
|
|
1550
|
-
);
|
|
1551
|
-
return { result: JSON.stringify(note, null, 2) };
|
|
1552
|
-
}
|
|
1553
|
-
// ========== Pipeline Tools ==========
|
|
1554
|
-
async listPipelines(input) {
|
|
1555
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1556
|
-
const params = new URLSearchParams();
|
|
1557
|
-
params.set("per_page", String(input.limit || 20));
|
|
1558
|
-
if (input.status) params.set("status", input.status);
|
|
1559
|
-
if (input.ref) params.set("ref", input.ref);
|
|
1560
|
-
const pipelines = await this.fetchApi(
|
|
1561
|
-
"GET",
|
|
1562
|
-
`/projects/${projectId}/pipelines?${params}`
|
|
1563
|
-
);
|
|
1564
|
-
return { result: JSON.stringify(pipelines, null, 2) };
|
|
1565
|
-
}
|
|
1566
|
-
async getPipeline(input) {
|
|
1567
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1568
|
-
const pipelineId = input.pipeline_id;
|
|
1569
|
-
const pipeline = await this.fetchApi(
|
|
1570
|
-
"GET",
|
|
1571
|
-
`/projects/${projectId}/pipelines/${pipelineId}`
|
|
1572
|
-
);
|
|
1573
|
-
return { result: JSON.stringify(pipeline, null, 2) };
|
|
1574
|
-
}
|
|
1575
|
-
async listPipelineJobs(input) {
|
|
1576
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1577
|
-
const pipelineId = input.pipeline_id;
|
|
1578
|
-
const params = new URLSearchParams();
|
|
1579
|
-
if (input.scope) params.set("scope[]", input.scope);
|
|
1580
|
-
const jobs = await this.fetchApi(
|
|
1581
|
-
"GET",
|
|
1582
|
-
`/projects/${projectId}/pipelines/${pipelineId}/jobs?${params}`
|
|
1583
|
-
);
|
|
1584
|
-
return { result: JSON.stringify(jobs, null, 2) };
|
|
1585
|
-
}
|
|
1586
|
-
async getJobLog(input) {
|
|
1587
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1588
|
-
const jobId = input.job_id;
|
|
1589
|
-
const url = `${this.config.instanceUrl}/api/v4/projects/${projectId}/jobs/${jobId}/trace`;
|
|
1590
|
-
const fetchFn = this.config.fetch || fetch;
|
|
1591
|
-
const response = await fetchFn(url, {
|
|
1592
|
-
method: "GET",
|
|
1593
|
-
headers: this.headers
|
|
1594
|
-
});
|
|
1595
|
-
if (!response.ok) {
|
|
1596
|
-
const errorText = await response.text();
|
|
1597
|
-
throw new Error(`GitLab API error ${response.status}: ${errorText}`);
|
|
1598
|
-
}
|
|
1599
|
-
const log = await response.text();
|
|
1600
|
-
const maxLength = 5e4;
|
|
1601
|
-
if (log.length > maxLength) {
|
|
1602
|
-
return {
|
|
1603
|
-
result: `[Log truncated, showing last ${maxLength} characters]
|
|
1604
|
-
|
|
1605
|
-
${log.slice(-maxLength)}`
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
return { result: log };
|
|
1609
|
-
}
|
|
1610
|
-
async retryJob(input) {
|
|
1611
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1612
|
-
const jobId = input.job_id;
|
|
1613
|
-
const job = await this.fetchApi(
|
|
1614
|
-
"POST",
|
|
1615
|
-
`/projects/${projectId}/jobs/${jobId}/retry`
|
|
1616
|
-
);
|
|
1617
|
-
return { result: JSON.stringify(job, null, 2) };
|
|
1618
|
-
}
|
|
1619
|
-
// ========== Repository Tools ==========
|
|
1620
|
-
async getFile(input) {
|
|
1621
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1622
|
-
const filePath = encodeURIComponent(input.file_path);
|
|
1623
|
-
const ref = input.ref || "HEAD";
|
|
1624
|
-
const file = await this.fetchApi(
|
|
1625
|
-
"GET",
|
|
1626
|
-
`/projects/${projectId}/repository/files/${filePath}?ref=${encodeURIComponent(ref)}`
|
|
1627
|
-
);
|
|
1628
|
-
if (file.encoding === "base64") {
|
|
1629
|
-
const decoded = Buffer.from(file.content, "base64").toString("utf-8");
|
|
1630
|
-
return { result: decoded };
|
|
1631
|
-
}
|
|
1632
|
-
return { result: file.content };
|
|
1633
|
-
}
|
|
1634
|
-
async listCommits(input) {
|
|
1635
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1636
|
-
const params = new URLSearchParams();
|
|
1637
|
-
params.set("per_page", String(input.limit || 20));
|
|
1638
|
-
if (input.ref) params.set("ref_name", input.ref);
|
|
1639
|
-
if (input.path) params.set("path", input.path);
|
|
1640
|
-
if (input.since) params.set("since", input.since);
|
|
1641
|
-
if (input.until) params.set("until", input.until);
|
|
1642
|
-
const commits = await this.fetchApi(
|
|
1643
|
-
"GET",
|
|
1644
|
-
`/projects/${projectId}/repository/commits?${params}`
|
|
1645
|
-
);
|
|
1646
|
-
return { result: JSON.stringify(commits, null, 2) };
|
|
1647
|
-
}
|
|
1648
|
-
async getCommitDiff(input) {
|
|
1649
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1650
|
-
const sha = input.sha;
|
|
1651
|
-
const diff = await this.fetchApi(
|
|
1652
|
-
"GET",
|
|
1653
|
-
`/projects/${projectId}/repository/commits/${sha}/diff`
|
|
1654
|
-
);
|
|
1655
|
-
return { result: JSON.stringify(diff, null, 2) };
|
|
1656
|
-
}
|
|
1657
|
-
async listBranches(input) {
|
|
1658
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1659
|
-
const params = new URLSearchParams();
|
|
1660
|
-
if (input.search) params.set("search", input.search);
|
|
1661
|
-
const branches = await this.fetchApi(
|
|
1662
|
-
"GET",
|
|
1663
|
-
`/projects/${projectId}/repository/branches?${params}`
|
|
1664
|
-
);
|
|
1665
|
-
return { result: JSON.stringify(branches, null, 2) };
|
|
1666
|
-
}
|
|
1667
|
-
// ========== Search Tools ==========
|
|
1668
|
-
async search(input) {
|
|
1669
|
-
const scope = input.scope;
|
|
1670
|
-
const searchQuery = input.search;
|
|
1671
|
-
const params = new URLSearchParams();
|
|
1672
|
-
params.set("scope", scope);
|
|
1673
|
-
params.set("search", searchQuery);
|
|
1674
|
-
params.set("per_page", String(input.limit || 20));
|
|
1675
|
-
let path4;
|
|
1676
|
-
if (input.project_id) {
|
|
1677
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1678
|
-
path4 = `/projects/${projectId}/search?${params}`;
|
|
1679
|
-
} else {
|
|
1680
|
-
path4 = `/search?${params}`;
|
|
1681
|
-
}
|
|
1682
|
-
const results = await this.fetchApi("GET", path4);
|
|
1683
|
-
return { result: JSON.stringify(results, null, 2) };
|
|
1684
|
-
}
|
|
1685
|
-
// ========== Project Tools ==========
|
|
1686
|
-
async getProject(input) {
|
|
1687
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1688
|
-
const project = await this.fetchApi("GET", `/projects/${projectId}`);
|
|
1689
|
-
return { result: JSON.stringify(project, null, 2) };
|
|
1690
|
-
}
|
|
1691
|
-
async listProjectMembers(input) {
|
|
1692
|
-
const projectId = this.encodeProjectId(input.project_id);
|
|
1693
|
-
const members = await this.fetchApi(
|
|
1694
|
-
"GET",
|
|
1695
|
-
`/projects/${projectId}/members`
|
|
1696
|
-
);
|
|
1697
|
-
return { result: JSON.stringify(members, null, 2) };
|
|
1698
|
-
}
|
|
1699
|
-
};
|
|
1700
|
-
function isGitLabApiTool(toolName) {
|
|
1701
|
-
return toolName.startsWith("gitlab_");
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
// src/gitlab-anthropic-tools.ts
|
|
1705
|
-
import * as fs2 from "fs/promises";
|
|
1706
|
-
import * as path2 from "path";
|
|
1707
|
-
import { spawn } from "child_process";
|
|
1708
|
-
var ANTHROPIC_TOOLS = [
|
|
1709
|
-
{
|
|
1710
|
-
name: "list_dir",
|
|
1711
|
-
description: `List directory contents. Shows files and subdirectories relative to the working directory.`,
|
|
1712
|
-
input_schema: {
|
|
1713
|
-
type: "object",
|
|
1714
|
-
properties: {
|
|
1715
|
-
directory: {
|
|
1716
|
-
type: "string",
|
|
1717
|
-
description: "Directory path relative to the working directory"
|
|
1718
|
-
}
|
|
1719
|
-
},
|
|
1720
|
-
required: ["directory"]
|
|
1721
|
-
}
|
|
1722
|
-
},
|
|
1723
|
-
{
|
|
1724
|
-
name: "read_file",
|
|
1725
|
-
description: `Read the contents of a file.`,
|
|
1726
|
-
input_schema: {
|
|
1727
|
-
type: "object",
|
|
1728
|
-
properties: {
|
|
1729
|
-
file_path: {
|
|
1730
|
-
type: "string",
|
|
1731
|
-
description: "The file path to read"
|
|
1732
|
-
}
|
|
1733
|
-
},
|
|
1734
|
-
required: ["file_path"]
|
|
1735
|
-
}
|
|
1736
|
-
},
|
|
1737
|
-
{
|
|
1738
|
-
name: "create_file_with_contents",
|
|
1739
|
-
description: `Create and write contents to a file.`,
|
|
1740
|
-
input_schema: {
|
|
1741
|
-
type: "object",
|
|
1742
|
-
properties: {
|
|
1743
|
-
file_path: {
|
|
1744
|
-
type: "string",
|
|
1745
|
-
description: "The file path to write to"
|
|
1746
|
-
},
|
|
1747
|
-
contents: {
|
|
1748
|
-
type: "string",
|
|
1749
|
-
description: "The contents to write"
|
|
1750
|
-
}
|
|
1751
|
-
},
|
|
1752
|
-
required: ["file_path", "contents"]
|
|
1753
|
-
}
|
|
1754
|
-
},
|
|
1755
|
-
{
|
|
1756
|
-
name: "edit_file",
|
|
1757
|
-
description: `Edit an existing file by replacing a string with a new string.`,
|
|
1758
|
-
input_schema: {
|
|
1759
|
-
type: "object",
|
|
1760
|
-
properties: {
|
|
1761
|
-
file_path: {
|
|
1762
|
-
type: "string",
|
|
1763
|
-
description: "The path of the file to edit"
|
|
1764
|
-
},
|
|
1765
|
-
old_str: {
|
|
1766
|
-
type: "string",
|
|
1767
|
-
description: "The string to replace (include context for uniqueness)"
|
|
1768
|
-
},
|
|
1769
|
-
new_str: {
|
|
1770
|
-
type: "string",
|
|
1771
|
-
description: "The new string value"
|
|
1772
|
-
}
|
|
1773
|
-
},
|
|
1774
|
-
required: ["file_path", "old_str", "new_str"]
|
|
1775
|
-
}
|
|
1776
|
-
},
|
|
1777
|
-
{
|
|
1778
|
-
name: "find_files",
|
|
1779
|
-
description: `Find files by name pattern. Uses glob-like matching.`,
|
|
1780
|
-
input_schema: {
|
|
1781
|
-
type: "object",
|
|
1782
|
-
properties: {
|
|
1783
|
-
name_pattern: {
|
|
1784
|
-
type: "string",
|
|
1785
|
-
description: 'The pattern to search for (e.g., "*.py", "test_*.js")'
|
|
1786
|
-
}
|
|
1787
|
-
},
|
|
1788
|
-
required: ["name_pattern"]
|
|
1789
|
-
}
|
|
1790
|
-
},
|
|
1791
|
-
{
|
|
1792
|
-
name: "mkdir",
|
|
1793
|
-
description: `Create a new directory.`,
|
|
1794
|
-
input_schema: {
|
|
1795
|
-
type: "object",
|
|
1796
|
-
properties: {
|
|
1797
|
-
directory_path: {
|
|
1798
|
-
type: "string",
|
|
1799
|
-
description: "The directory path to create"
|
|
1800
|
-
}
|
|
1801
|
-
},
|
|
1802
|
-
required: ["directory_path"]
|
|
1803
|
-
}
|
|
1804
|
-
},
|
|
1805
|
-
{
|
|
1806
|
-
name: "grep",
|
|
1807
|
-
description: `Search for text patterns within files.`,
|
|
1808
|
-
input_schema: {
|
|
1809
|
-
type: "object",
|
|
1810
|
-
properties: {
|
|
1811
|
-
pattern: {
|
|
1812
|
-
type: "string",
|
|
1813
|
-
description: "The text pattern to search for"
|
|
1814
|
-
},
|
|
1815
|
-
search_directory: {
|
|
1816
|
-
type: "string",
|
|
1817
|
-
description: 'The directory to search in (default: ".")'
|
|
1818
|
-
},
|
|
1819
|
-
case_insensitive: {
|
|
1820
|
-
type: "boolean",
|
|
1821
|
-
description: "Whether to ignore case (default: false)"
|
|
1822
|
-
}
|
|
1823
|
-
},
|
|
1824
|
-
required: ["pattern"]
|
|
1825
|
-
}
|
|
1826
|
-
},
|
|
1827
|
-
{
|
|
1828
|
-
name: "run_command",
|
|
1829
|
-
description: `Run a shell command. Note: git commands should use run_git_command instead.`,
|
|
1830
|
-
input_schema: {
|
|
1831
|
-
type: "object",
|
|
1832
|
-
properties: {
|
|
1833
|
-
program: {
|
|
1834
|
-
type: "string",
|
|
1835
|
-
description: 'The program to execute (e.g., "npm", "python")'
|
|
1836
|
-
},
|
|
1837
|
-
args: {
|
|
1838
|
-
type: "string",
|
|
1839
|
-
description: "Arguments as a single string"
|
|
1840
|
-
}
|
|
1841
|
-
},
|
|
1842
|
-
required: ["program"]
|
|
1843
|
-
}
|
|
1844
|
-
},
|
|
1845
|
-
{
|
|
1846
|
-
name: "run_git_command",
|
|
1847
|
-
description: `Run a git command in the repository.`,
|
|
1848
|
-
input_schema: {
|
|
1849
|
-
type: "object",
|
|
1850
|
-
properties: {
|
|
1851
|
-
command: {
|
|
1852
|
-
type: "string",
|
|
1853
|
-
description: 'Git command (e.g., "status", "log", "diff")'
|
|
1854
|
-
},
|
|
1855
|
-
args: {
|
|
1856
|
-
type: "string",
|
|
1857
|
-
description: "Git command arguments"
|
|
1858
|
-
}
|
|
1859
|
-
},
|
|
1860
|
-
required: ["command"]
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
];
|
|
1864
|
-
var AnthropicToolExecutor = class {
|
|
1865
|
-
workingDirectory;
|
|
1866
|
-
constructor(workingDirectory) {
|
|
1867
|
-
this.workingDirectory = workingDirectory;
|
|
1868
|
-
}
|
|
1869
|
-
/**
|
|
1870
|
-
* Execute a tool by name with given input
|
|
1871
|
-
*/
|
|
1872
|
-
async execute(toolName, input) {
|
|
1873
|
-
try {
|
|
1874
|
-
switch (toolName) {
|
|
1875
|
-
case "list_dir":
|
|
1876
|
-
return this.listDir(input.directory);
|
|
1877
|
-
case "read_file":
|
|
1878
|
-
return this.readFile(input.file_path);
|
|
1879
|
-
case "create_file_with_contents":
|
|
1880
|
-
return this.writeFile(input.file_path, input.contents);
|
|
1881
|
-
case "edit_file":
|
|
1882
|
-
return this.editFile(
|
|
1883
|
-
input.file_path,
|
|
1884
|
-
input.old_str,
|
|
1885
|
-
input.new_str
|
|
1886
|
-
);
|
|
1887
|
-
case "find_files":
|
|
1888
|
-
return this.findFiles(input.name_pattern);
|
|
1889
|
-
case "mkdir":
|
|
1890
|
-
return this.mkdir(input.directory_path);
|
|
1891
|
-
case "grep":
|
|
1892
|
-
return this.grep(
|
|
1893
|
-
input.pattern,
|
|
1894
|
-
input.search_directory,
|
|
1895
|
-
input.case_insensitive
|
|
1896
|
-
);
|
|
1897
|
-
case "run_command":
|
|
1898
|
-
return this.runCommand(input.program, input.args);
|
|
1899
|
-
case "run_git_command":
|
|
1900
|
-
return this.runGitCommand(input.command, input.args);
|
|
1901
|
-
default:
|
|
1902
|
-
return { result: "", error: `Unknown tool: ${toolName}` };
|
|
1903
|
-
}
|
|
1904
|
-
} catch (error) {
|
|
1905
|
-
return {
|
|
1906
|
-
result: "",
|
|
1907
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1908
|
-
};
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
resolvePath(filePath) {
|
|
1912
|
-
if (path2.isAbsolute(filePath)) {
|
|
1913
|
-
return filePath;
|
|
1914
|
-
}
|
|
1915
|
-
return path2.resolve(this.workingDirectory, filePath);
|
|
1916
|
-
}
|
|
1917
|
-
async listDir(directory) {
|
|
1918
|
-
const dirPath = this.resolvePath(directory || ".");
|
|
1919
|
-
const entries = await fs2.readdir(dirPath, { withFileTypes: true });
|
|
1920
|
-
const result = entries.map((entry) => {
|
|
1921
|
-
const type = entry.isDirectory() ? "d" : "-";
|
|
1922
|
-
return `${type} ${entry.name}`;
|
|
1923
|
-
}).join("\n");
|
|
1924
|
-
return { result };
|
|
1925
|
-
}
|
|
1926
|
-
async readFile(filePath) {
|
|
1927
|
-
const fullPath = this.resolvePath(filePath);
|
|
1928
|
-
const content = await fs2.readFile(fullPath, "utf-8");
|
|
1929
|
-
return { result: content };
|
|
1930
|
-
}
|
|
1931
|
-
async writeFile(filePath, contents) {
|
|
1932
|
-
const fullPath = this.resolvePath(filePath);
|
|
1933
|
-
await fs2.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
1934
|
-
await fs2.writeFile(fullPath, contents, "utf-8");
|
|
1935
|
-
return { result: `File written successfully: ${filePath}` };
|
|
1936
|
-
}
|
|
1937
|
-
async editFile(filePath, oldStr, newStr) {
|
|
1938
|
-
const fullPath = this.resolvePath(filePath);
|
|
1939
|
-
const content = await fs2.readFile(fullPath, "utf-8");
|
|
1940
|
-
if (!content.includes(oldStr)) {
|
|
1941
|
-
return { result: "", error: `String not found in file: "${oldStr.substring(0, 50)}..."` };
|
|
1942
|
-
}
|
|
1943
|
-
const newContent = content.replace(oldStr, newStr);
|
|
1944
|
-
await fs2.writeFile(fullPath, newContent, "utf-8");
|
|
1945
|
-
return { result: `File edited successfully: ${filePath}` };
|
|
1946
|
-
}
|
|
1947
|
-
async findFiles(namePattern) {
|
|
1948
|
-
const results = [];
|
|
1949
|
-
const regex = new RegExp("^" + namePattern.replace(/\*/g, ".*").replace(/\?/g, ".") + "$");
|
|
1950
|
-
const search = async (dir, relativePath = "") => {
|
|
1951
|
-
try {
|
|
1952
|
-
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
1953
|
-
for (const entry of entries) {
|
|
1954
|
-
const entryRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
1955
|
-
if (entry.isDirectory()) {
|
|
1956
|
-
if (!["node_modules", ".git", "dist", "build", "__pycache__"].includes(entry.name)) {
|
|
1957
|
-
await search(path2.join(dir, entry.name), entryRelativePath);
|
|
1958
|
-
}
|
|
1959
|
-
} else if (regex.test(entry.name)) {
|
|
1960
|
-
results.push(entryRelativePath);
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
} catch {
|
|
1964
|
-
}
|
|
1965
|
-
};
|
|
1966
|
-
await search(this.workingDirectory);
|
|
1967
|
-
return { result: results.join("\n") || "No files found" };
|
|
1968
|
-
}
|
|
1969
|
-
async mkdir(directoryPath) {
|
|
1970
|
-
const fullPath = this.resolvePath(directoryPath);
|
|
1971
|
-
await fs2.mkdir(fullPath, { recursive: true });
|
|
1972
|
-
return { result: `Directory created: ${directoryPath}` };
|
|
1973
|
-
}
|
|
1974
|
-
async grep(pattern, searchDirectory, caseInsensitive) {
|
|
1975
|
-
const results = [];
|
|
1976
|
-
const flags = caseInsensitive ? "gi" : "g";
|
|
1977
|
-
const regex = new RegExp(pattern, flags);
|
|
1978
|
-
const searchDir = this.resolvePath(searchDirectory || ".");
|
|
1979
|
-
const search = async (dir, relativePath = "") => {
|
|
1980
|
-
try {
|
|
1981
|
-
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
1982
|
-
for (const entry of entries) {
|
|
1983
|
-
const entryRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
1984
|
-
const fullPath = path2.join(dir, entry.name);
|
|
1985
|
-
if (entry.isDirectory()) {
|
|
1986
|
-
if (!["node_modules", ".git", "dist", "build", "__pycache__"].includes(entry.name)) {
|
|
1987
|
-
await search(fullPath, entryRelativePath);
|
|
1988
|
-
}
|
|
1989
|
-
} else {
|
|
1990
|
-
try {
|
|
1991
|
-
const content = await fs2.readFile(fullPath, "utf-8");
|
|
1992
|
-
const lines = content.split("\n");
|
|
1993
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1994
|
-
if (regex.test(lines[i])) {
|
|
1995
|
-
results.push(`${entryRelativePath}:${i + 1}: ${lines[i].trim()}`);
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
} catch {
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
} catch {
|
|
2003
|
-
}
|
|
2004
|
-
};
|
|
2005
|
-
await search(searchDir);
|
|
2006
|
-
return { result: results.slice(0, 100).join("\n") || "No matches found" };
|
|
2007
|
-
}
|
|
2008
|
-
runCommand(program, args) {
|
|
2009
|
-
if (program === "git") {
|
|
2010
|
-
return Promise.resolve({
|
|
2011
|
-
result: "",
|
|
2012
|
-
error: "Use run_git_command for git operations"
|
|
2013
|
-
});
|
|
2014
|
-
}
|
|
2015
|
-
const parsedArgs = args ? args.match(/(?:[^\s"]+|"[^"]*")+/g) || [] : [];
|
|
2016
|
-
const cleanedArgs = parsedArgs.map((arg) => arg.replace(/^"(.*)"$/, "$1"));
|
|
2017
|
-
return this.executeCommand(program, cleanedArgs);
|
|
2018
|
-
}
|
|
2019
|
-
runGitCommand(command, args) {
|
|
2020
|
-
const gitArgs = [command];
|
|
2021
|
-
if (args) {
|
|
2022
|
-
const parsedArgs = args.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
2023
|
-
gitArgs.push(...parsedArgs.map((arg) => arg.replace(/^"(.*)"$/, "$1")));
|
|
2024
|
-
}
|
|
2025
|
-
return this.executeCommand("git", gitArgs);
|
|
2026
|
-
}
|
|
2027
|
-
executeCommand(program, args) {
|
|
2028
|
-
return new Promise((resolve3) => {
|
|
2029
|
-
const child = spawn(program, args, {
|
|
2030
|
-
cwd: this.workingDirectory,
|
|
2031
|
-
timeout: 3e4
|
|
2032
|
-
});
|
|
2033
|
-
let stdout = "";
|
|
2034
|
-
let stderr = "";
|
|
2035
|
-
child.stdout?.on("data", (data) => {
|
|
2036
|
-
stdout += data.toString();
|
|
2037
|
-
});
|
|
2038
|
-
child.stderr?.on("data", (data) => {
|
|
2039
|
-
stderr += data.toString();
|
|
2040
|
-
});
|
|
2041
|
-
child.on("error", (error) => {
|
|
2042
|
-
resolve3({
|
|
2043
|
-
result: "",
|
|
2044
|
-
error: `Command failed: ${error.message}`
|
|
2045
|
-
});
|
|
2046
|
-
});
|
|
2047
|
-
child.on("close", (exitCode) => {
|
|
2048
|
-
if (exitCode !== 0 && stderr) {
|
|
2049
|
-
resolve3({
|
|
2050
|
-
result: stdout,
|
|
2051
|
-
error: stderr
|
|
2052
|
-
});
|
|
2053
|
-
} else {
|
|
2054
|
-
resolve3({
|
|
2055
|
-
result: stdout || stderr || `Command completed with exit code ${exitCode}`
|
|
2056
|
-
});
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
|
-
};
|
|
2062
|
-
|
|
2063
914
|
// src/gitlab-project-detector.ts
|
|
2064
|
-
import { spawn
|
|
2065
|
-
import * as
|
|
915
|
+
import { spawn } from "child_process";
|
|
916
|
+
import * as path2 from "path";
|
|
2066
917
|
|
|
2067
918
|
// src/gitlab-project-cache.ts
|
|
2068
919
|
var GitLabProjectCache = class {
|
|
@@ -2145,7 +996,7 @@ var GitLabProjectCache = class {
|
|
|
2145
996
|
};
|
|
2146
997
|
|
|
2147
998
|
// src/gitlab-project-detector.ts
|
|
2148
|
-
var
|
|
999
|
+
var debugLog2 = (..._args) => {
|
|
2149
1000
|
};
|
|
2150
1001
|
var GitLabProjectDetector = class {
|
|
2151
1002
|
config;
|
|
@@ -2168,41 +1019,41 @@ var GitLabProjectDetector = class {
|
|
|
2168
1019
|
* @returns The detected project or null if detection fails
|
|
2169
1020
|
*/
|
|
2170
1021
|
async detectProject(workingDirectory, remoteName = "origin") {
|
|
2171
|
-
const cacheKey =
|
|
1022
|
+
const cacheKey = path2.resolve(workingDirectory);
|
|
2172
1023
|
const cached = this.cache.get(cacheKey);
|
|
2173
1024
|
if (cached) {
|
|
2174
1025
|
return cached;
|
|
2175
1026
|
}
|
|
2176
1027
|
try {
|
|
2177
|
-
|
|
1028
|
+
debugLog2(`[GitLabProjectDetector] Getting git remote URL from: ${workingDirectory}`);
|
|
2178
1029
|
const remoteUrl = await this.getGitRemoteUrl(workingDirectory, remoteName);
|
|
2179
1030
|
if (!remoteUrl) {
|
|
2180
|
-
|
|
1031
|
+
debugLog2(`[GitLabProjectDetector] No git remote URL found`);
|
|
2181
1032
|
return null;
|
|
2182
1033
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
1034
|
+
debugLog2(`[GitLabProjectDetector] Git remote URL: ${remoteUrl}`);
|
|
1035
|
+
debugLog2(
|
|
2185
1036
|
`[GitLabProjectDetector] Parsing project path from URL (instance: ${this.config.instanceUrl})`
|
|
2186
1037
|
);
|
|
2187
1038
|
const projectPath = this.parseGitRemoteUrl(remoteUrl, this.config.instanceUrl);
|
|
2188
1039
|
if (!projectPath) {
|
|
2189
|
-
|
|
1040
|
+
debugLog2(
|
|
2190
1041
|
`[GitLabProjectDetector] Could not parse project path from URL (remote doesn't match instance)`
|
|
2191
1042
|
);
|
|
2192
1043
|
return null;
|
|
2193
1044
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
1045
|
+
debugLog2(`[GitLabProjectDetector] Parsed project path: ${projectPath}`);
|
|
1046
|
+
debugLog2(`[GitLabProjectDetector] Fetching project from GitLab API: ${projectPath}`);
|
|
2196
1047
|
const project = await this.getProjectByPath(projectPath);
|
|
2197
|
-
|
|
1048
|
+
debugLog2(`[GitLabProjectDetector] \u2713 Project fetched successfully:`, project);
|
|
2198
1049
|
this.cache.set(cacheKey, project);
|
|
2199
1050
|
return project;
|
|
2200
1051
|
} catch (error) {
|
|
2201
1052
|
if (error instanceof GitLabError) {
|
|
2202
|
-
|
|
1053
|
+
debugLog2(`[GitLabProjectDetector] GitLab API error:`, error.message || error);
|
|
2203
1054
|
return null;
|
|
2204
1055
|
}
|
|
2205
|
-
|
|
1056
|
+
debugLog2(`[GitLabProjectDetector] Unexpected error:`, error);
|
|
2206
1057
|
console.warn(`Failed to auto-detect GitLab project: ${error}`);
|
|
2207
1058
|
return null;
|
|
2208
1059
|
}
|
|
@@ -2253,8 +1104,8 @@ var GitLabProjectDetector = class {
|
|
|
2253
1104
|
* @returns The remote URL or null if not found
|
|
2254
1105
|
*/
|
|
2255
1106
|
async getGitRemoteUrl(workingDirectory, remoteName = "origin") {
|
|
2256
|
-
return new Promise((
|
|
2257
|
-
const child =
|
|
1107
|
+
return new Promise((resolve2) => {
|
|
1108
|
+
const child = spawn("git", ["config", "--get", `remote.${remoteName}.url`], {
|
|
2258
1109
|
cwd: workingDirectory,
|
|
2259
1110
|
timeout: this.config.gitTimeout
|
|
2260
1111
|
});
|
|
@@ -2268,13 +1119,13 @@ var GitLabProjectDetector = class {
|
|
|
2268
1119
|
});
|
|
2269
1120
|
child.on("close", (exitCode) => {
|
|
2270
1121
|
if (exitCode === 0 && stdout.trim()) {
|
|
2271
|
-
|
|
1122
|
+
resolve2(stdout.trim());
|
|
2272
1123
|
} else {
|
|
2273
|
-
|
|
1124
|
+
resolve2(null);
|
|
2274
1125
|
}
|
|
2275
1126
|
});
|
|
2276
1127
|
child.on("error", () => {
|
|
2277
|
-
|
|
1128
|
+
resolve2(null);
|
|
2278
1129
|
});
|
|
2279
1130
|
});
|
|
2280
1131
|
}
|
|
@@ -2330,21 +1181,20 @@ var GitLabProjectDetector = class {
|
|
|
2330
1181
|
}
|
|
2331
1182
|
};
|
|
2332
1183
|
export {
|
|
2333
|
-
ANTHROPIC_TOOLS,
|
|
2334
|
-
AnthropicToolExecutor,
|
|
2335
1184
|
BUNDLED_CLIENT_ID,
|
|
2336
|
-
|
|
1185
|
+
DEFAULT_AI_GATEWAY_URL,
|
|
2337
1186
|
GITLAB_COM_URL,
|
|
2338
1187
|
GitLabAgenticLanguageModel,
|
|
2339
|
-
|
|
1188
|
+
GitLabDirectAccessClient,
|
|
2340
1189
|
GitLabError,
|
|
2341
1190
|
GitLabOAuthManager,
|
|
2342
1191
|
GitLabProjectCache,
|
|
2343
1192
|
GitLabProjectDetector,
|
|
1193
|
+
MODEL_ID_TO_ANTHROPIC_MODEL,
|
|
2344
1194
|
OAUTH_SCOPES,
|
|
2345
1195
|
TOKEN_EXPIRY_SKEW_MS,
|
|
2346
1196
|
createGitLab,
|
|
2347
|
-
|
|
2348
|
-
|
|
1197
|
+
getAnthropicModelForModelId,
|
|
1198
|
+
gitlab
|
|
2349
1199
|
};
|
|
2350
1200
|
//# sourceMappingURL=index.mjs.map
|