@daghis/teamcity-mcp 1.9.6 → 1.10.1

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/dist/index.js CHANGED
@@ -261,17 +261,11 @@ var init_build_status_manager = __esm({
261
261
  buildData = response.data;
262
262
  } else {
263
263
  const locator = this.buildLocator(options);
264
- const response = await this.client.builds.getMultipleBuilds(
264
+ const response = await this.client.builds.getBuild(
265
265
  locator,
266
266
  this.getFieldSelection(options)
267
267
  );
268
- const data = response.data;
269
- if (!Array.isArray(data.build) || data.build.length === 0) {
270
- throw new BuildNotFoundError(
271
- `No build found for number ${options.buildNumber} in ${options.buildTypeId}`
272
- );
273
- }
274
- buildData = data.build[0];
268
+ buildData = response.data;
275
269
  }
276
270
  if (buildData == null) {
277
271
  throw new BuildNotFoundError("Build data is undefined");
@@ -936,6 +930,137 @@ var ResolutionTypeEnum = {
936
930
  AtTime: "atTime"
937
931
  };
938
932
 
933
+ // src/teamcity/agent-requirements-manager.ts
934
+ var JSON_HEADERS = {
935
+ headers: {
936
+ "Content-Type": "application/json",
937
+ Accept: "application/json"
938
+ }
939
+ };
940
+ var JSON_GET_HEADERS = {
941
+ headers: {
942
+ Accept: "application/json"
943
+ }
944
+ };
945
+ var toStringRecord = (input) => {
946
+ if (!input) {
947
+ return {};
948
+ }
949
+ return Object.fromEntries(
950
+ Object.entries(input).map(([name, value]) => {
951
+ if (value === void 0 || value === null) {
952
+ return [name, ""];
953
+ }
954
+ if (typeof value === "boolean") {
955
+ return [name, value ? "true" : "false"];
956
+ }
957
+ return [name, String(value)];
958
+ })
959
+ );
960
+ };
961
+ var propertiesToRecord = (properties) => {
962
+ if (properties == null) {
963
+ return {};
964
+ }
965
+ const propertyEntries = properties.property;
966
+ const items = Array.isArray(propertyEntries) ? propertyEntries : propertyEntries != null ? [propertyEntries] : [];
967
+ const record = {};
968
+ for (const item of items) {
969
+ if (!item?.name) {
970
+ continue;
971
+ }
972
+ record[item.name] = item.value != null ? String(item.value) : "";
973
+ }
974
+ return record;
975
+ };
976
+ var recordToProperties = (record) => {
977
+ const entries = Object.entries(record);
978
+ if (entries.length === 0) {
979
+ return void 0;
980
+ }
981
+ return {
982
+ property: entries.map(([name, value]) => ({ name, value }))
983
+ };
984
+ };
985
+ var mergeRecords = (base, override) => ({
986
+ ...base,
987
+ ...override
988
+ });
989
+ var AgentRequirementsManager = class {
990
+ constructor(client) {
991
+ this.client = client;
992
+ }
993
+ async addRequirement(input) {
994
+ const { buildTypeId } = input;
995
+ const payload = this.buildPayload(void 0, input);
996
+ const response = await this.client.modules.buildTypes.addAgentRequirementToBuildType(
997
+ buildTypeId,
998
+ void 0,
999
+ payload,
1000
+ JSON_HEADERS
1001
+ );
1002
+ const id = response.data?.id;
1003
+ if (!id) {
1004
+ throw new Error("TeamCity did not return an agent requirement identifier.");
1005
+ }
1006
+ return { id };
1007
+ }
1008
+ async updateRequirement(requirementId, input) {
1009
+ const { buildTypeId } = input;
1010
+ const existing = await this.fetchRequirement(buildTypeId, requirementId);
1011
+ if (!existing) {
1012
+ throw new Error(
1013
+ `Agent requirement ${requirementId} was not found on ${buildTypeId}; verify the ID or update via the TeamCity UI.`
1014
+ );
1015
+ }
1016
+ const payload = this.buildPayload(existing, input);
1017
+ await this.client.modules.buildTypes.replaceAgentRequirement(
1018
+ buildTypeId,
1019
+ requirementId,
1020
+ void 0,
1021
+ payload,
1022
+ JSON_HEADERS
1023
+ );
1024
+ return { id: requirementId };
1025
+ }
1026
+ async deleteRequirement(buildTypeId, requirementId) {
1027
+ await this.client.modules.buildTypes.deleteAgentRequirement(
1028
+ buildTypeId,
1029
+ requirementId,
1030
+ JSON_HEADERS
1031
+ );
1032
+ }
1033
+ async fetchRequirement(buildTypeId, requirementId) {
1034
+ try {
1035
+ const response = await this.client.modules.buildTypes.getAgentRequirement(
1036
+ buildTypeId,
1037
+ requirementId,
1038
+ "id,type,disabled,properties(property(name,value))",
1039
+ JSON_GET_HEADERS
1040
+ );
1041
+ return response.data;
1042
+ } catch (error2) {
1043
+ if (typeof error2 === "object" && error2 !== null && "response" in error2 && error2.response?.status === 404) {
1044
+ return null;
1045
+ }
1046
+ throw error2;
1047
+ }
1048
+ }
1049
+ buildPayload(existing, input) {
1050
+ const baseProps = propertiesToRecord(existing?.properties);
1051
+ const mergedProps = mergeRecords(baseProps, toStringRecord(input.properties));
1052
+ const payload = {
1053
+ ...existing ?? {},
1054
+ disabled: input.disabled ?? existing?.disabled
1055
+ };
1056
+ const properties = recordToProperties(mergedProps);
1057
+ if (properties) {
1058
+ payload.properties = properties;
1059
+ }
1060
+ return payload;
1061
+ }
1062
+ };
1063
+
939
1064
  // src/teamcity/artifact-manager.ts
940
1065
  var import_axios = require("axios");
941
1066
  init_errors();
@@ -1817,6 +1942,356 @@ var BuildConfigurationUpdateManager = class {
1817
1942
  }
1818
1943
  };
1819
1944
 
1945
+ // src/teamcity/build-dependency-manager.ts
1946
+ var JSON_HEADERS2 = {
1947
+ headers: {
1948
+ "Content-Type": "application/json",
1949
+ Accept: "application/json"
1950
+ }
1951
+ };
1952
+ var JSON_GET_HEADERS2 = {
1953
+ headers: {
1954
+ Accept: "application/json"
1955
+ }
1956
+ };
1957
+ var defaultTypeFor = (dependencyType) => {
1958
+ switch (dependencyType) {
1959
+ case "artifact":
1960
+ return void 0;
1961
+ case "snapshot":
1962
+ return void 0;
1963
+ default:
1964
+ return void 0;
1965
+ }
1966
+ };
1967
+ var toStringRecord2 = (input) => {
1968
+ if (!input) {
1969
+ return {};
1970
+ }
1971
+ const entries = Object.entries(input).map(([name, value]) => {
1972
+ if (value === void 0 || value === null) {
1973
+ return [name, ""];
1974
+ }
1975
+ if (typeof value === "boolean") {
1976
+ return [name, value ? "true" : "false"];
1977
+ }
1978
+ return [name, String(value)];
1979
+ });
1980
+ return Object.fromEntries(entries);
1981
+ };
1982
+ var propertiesToRecord2 = (properties) => {
1983
+ if (properties == null) {
1984
+ return {};
1985
+ }
1986
+ const propertyEntries = properties.property;
1987
+ const collection = Array.isArray(propertyEntries) ? propertyEntries : propertyEntries != null ? [propertyEntries] : [];
1988
+ const map = {};
1989
+ for (const item of collection) {
1990
+ if (!item?.name) {
1991
+ continue;
1992
+ }
1993
+ map[item.name] = item.value != null ? String(item.value) : "";
1994
+ }
1995
+ return map;
1996
+ };
1997
+ var recordToProperties2 = (record) => {
1998
+ const entries = Object.entries(record);
1999
+ if (entries.length === 0) {
2000
+ return void 0;
2001
+ }
2002
+ return {
2003
+ property: entries.map(([name, value]) => ({ name, value }))
2004
+ };
2005
+ };
2006
+ var mergeRecords2 = (base, override) => {
2007
+ const merged = { ...base };
2008
+ for (const [key, value] of Object.entries(override)) {
2009
+ merged[key] = value;
2010
+ }
2011
+ return merged;
2012
+ };
2013
+ var BuildDependencyManager = class {
2014
+ constructor(client) {
2015
+ this.client = client;
2016
+ }
2017
+ async addDependency(input) {
2018
+ const { buildTypeId, dependencyType, dependsOn } = input;
2019
+ if (!dependsOn || dependsOn.trim() === "") {
2020
+ throw new Error(
2021
+ "dependsOn is required when adding a dependency; specify the upstream build configuration ID or use the TeamCity UI."
2022
+ );
2023
+ }
2024
+ const payload = this.buildPayload(dependencyType, void 0, {
2025
+ ...input,
2026
+ dependsOn
2027
+ });
2028
+ const response = await this.createDependency(dependencyType, buildTypeId, payload);
2029
+ const id = response.data?.id;
2030
+ if (!id) {
2031
+ throw new Error("TeamCity did not return a dependency identifier. Verify server response.");
2032
+ }
2033
+ return { id };
2034
+ }
2035
+ async updateDependency(dependencyId, input) {
2036
+ const { buildTypeId, dependencyType } = input;
2037
+ const existing = await this.fetchDependency(dependencyType, buildTypeId, dependencyId);
2038
+ if (!existing) {
2039
+ throw new Error(
2040
+ `Dependency ${dependencyId} was not found on ${buildTypeId}; verify the identifier or update via the TeamCity UI.`
2041
+ );
2042
+ }
2043
+ const payload = this.buildPayload(dependencyType, existing, input);
2044
+ await this.replaceDependency(dependencyType, buildTypeId, dependencyId, payload);
2045
+ return { id: dependencyId };
2046
+ }
2047
+ async deleteDependency(dependencyType, buildTypeId, dependencyId) {
2048
+ if (!dependencyId) {
2049
+ throw new Error("dependencyId is required to delete a dependency.");
2050
+ }
2051
+ if (dependencyType === "artifact") {
2052
+ await this.client.modules.buildTypes.deleteArtifactDependency(
2053
+ buildTypeId,
2054
+ dependencyId,
2055
+ JSON_HEADERS2
2056
+ );
2057
+ return;
2058
+ }
2059
+ await this.client.modules.buildTypes.deleteSnapshotDependency(
2060
+ buildTypeId,
2061
+ dependencyId,
2062
+ JSON_HEADERS2
2063
+ );
2064
+ }
2065
+ async createDependency(dependencyType, buildTypeId, payload) {
2066
+ if (dependencyType === "artifact") {
2067
+ return this.client.modules.buildTypes.addArtifactDependencyToBuildType(
2068
+ buildTypeId,
2069
+ void 0,
2070
+ payload,
2071
+ JSON_HEADERS2
2072
+ );
2073
+ }
2074
+ return this.client.modules.buildTypes.addSnapshotDependencyToBuildType(
2075
+ buildTypeId,
2076
+ void 0,
2077
+ payload,
2078
+ JSON_HEADERS2
2079
+ );
2080
+ }
2081
+ async replaceDependency(dependencyType, buildTypeId, dependencyId, payload) {
2082
+ if (dependencyType === "artifact") {
2083
+ return this.client.modules.buildTypes.replaceArtifactDependency(
2084
+ buildTypeId,
2085
+ dependencyId,
2086
+ void 0,
2087
+ payload,
2088
+ JSON_HEADERS2
2089
+ );
2090
+ }
2091
+ return this.client.modules.buildTypes.replaceSnapshotDependency(
2092
+ buildTypeId,
2093
+ dependencyId,
2094
+ void 0,
2095
+ payload,
2096
+ JSON_HEADERS2
2097
+ );
2098
+ }
2099
+ async fetchDependency(dependencyType, buildTypeId, dependencyId) {
2100
+ try {
2101
+ if (dependencyType === "artifact") {
2102
+ const response2 = await this.client.modules.buildTypes.getArtifactDependency(
2103
+ buildTypeId,
2104
+ dependencyId,
2105
+ "id,type,disabled,properties(property(name,value)),'source-buildType'(id)",
2106
+ JSON_GET_HEADERS2
2107
+ );
2108
+ return response2.data;
2109
+ }
2110
+ const response = await this.client.modules.buildTypes.getSnapshotDependency(
2111
+ buildTypeId,
2112
+ dependencyId,
2113
+ "id,type,disabled,properties(property(name,value)),'source-buildType'(id)",
2114
+ JSON_GET_HEADERS2
2115
+ );
2116
+ return response.data;
2117
+ } catch (error2) {
2118
+ if (this.isNotFound(error2)) {
2119
+ return null;
2120
+ }
2121
+ throw error2;
2122
+ }
2123
+ }
2124
+ buildPayload(dependencyType, existing, input) {
2125
+ const baseProps = propertiesToRecord2(existing?.properties);
2126
+ const mergedProps = mergeRecords2(baseProps, toStringRecord2(input.properties));
2127
+ const properties = recordToProperties2(mergedProps);
2128
+ const resolvedType = input.type ?? existing?.type ?? defaultTypeFor(dependencyType);
2129
+ const payload = {
2130
+ ...existing ?? {},
2131
+ disabled: input.disabled ?? existing?.disabled
2132
+ };
2133
+ if (resolvedType) {
2134
+ payload.type = resolvedType;
2135
+ }
2136
+ if (properties) {
2137
+ payload.properties = properties;
2138
+ }
2139
+ const dependsOn = input.dependsOn ?? existing?.["source-buildType"]?.id;
2140
+ if (dependsOn) {
2141
+ payload["source-buildType"] = { id: dependsOn };
2142
+ } else {
2143
+ delete payload["source-buildType"];
2144
+ }
2145
+ return payload;
2146
+ }
2147
+ isNotFound(error2) {
2148
+ return Boolean(
2149
+ typeof error2 === "object" && error2 !== null && "response" in error2 && error2.response?.status === 404
2150
+ );
2151
+ }
2152
+ };
2153
+
2154
+ // src/teamcity/build-feature-manager.ts
2155
+ var JSON_HEADERS3 = {
2156
+ headers: {
2157
+ "Content-Type": "application/json",
2158
+ Accept: "application/json"
2159
+ }
2160
+ };
2161
+ var JSON_GET_HEADERS3 = {
2162
+ headers: {
2163
+ Accept: "application/json"
2164
+ }
2165
+ };
2166
+ var toStringRecord3 = (input) => {
2167
+ if (!input) {
2168
+ return {};
2169
+ }
2170
+ return Object.fromEntries(
2171
+ Object.entries(input).map(([name, value]) => {
2172
+ if (value === void 0 || value === null) {
2173
+ return [name, ""];
2174
+ }
2175
+ if (typeof value === "boolean") {
2176
+ return [name, value ? "true" : "false"];
2177
+ }
2178
+ return [name, String(value)];
2179
+ })
2180
+ );
2181
+ };
2182
+ var propertiesToRecord3 = (properties) => {
2183
+ if (properties == null) {
2184
+ return {};
2185
+ }
2186
+ const propertyEntries = properties.property;
2187
+ const items = Array.isArray(propertyEntries) ? propertyEntries : propertyEntries != null ? [propertyEntries] : [];
2188
+ const record = {};
2189
+ for (const item of items) {
2190
+ if (!item?.name) {
2191
+ continue;
2192
+ }
2193
+ record[item.name] = item.value != null ? String(item.value) : "";
2194
+ }
2195
+ return record;
2196
+ };
2197
+ var recordToProperties3 = (record) => {
2198
+ const entries = Object.entries(record);
2199
+ if (entries.length === 0) {
2200
+ return void 0;
2201
+ }
2202
+ return {
2203
+ property: entries.map(([name, value]) => ({ name, value }))
2204
+ };
2205
+ };
2206
+ var mergeRecords3 = (base, override) => ({
2207
+ ...base,
2208
+ ...override
2209
+ });
2210
+ var BuildFeatureManager = class {
2211
+ constructor(client) {
2212
+ this.client = client;
2213
+ }
2214
+ async addFeature(input) {
2215
+ const { buildTypeId, type } = input;
2216
+ if (!type || type.trim() === "") {
2217
+ throw new Error("type is required when adding a build feature.");
2218
+ }
2219
+ const payload = this.buildPayload(void 0, input);
2220
+ payload.type = type;
2221
+ const response = await this.client.modules.buildTypes.addBuildFeatureToBuildType(
2222
+ buildTypeId,
2223
+ void 0,
2224
+ payload,
2225
+ JSON_HEADERS3
2226
+ );
2227
+ const id = response.data?.id;
2228
+ if (!id) {
2229
+ throw new Error("TeamCity did not return a feature identifier.");
2230
+ }
2231
+ return { id };
2232
+ }
2233
+ async updateFeature(featureId, input) {
2234
+ const { buildTypeId } = input;
2235
+ const existing = await this.fetchFeature(buildTypeId, featureId);
2236
+ if (!existing) {
2237
+ throw new Error(
2238
+ `Feature ${featureId} was not found on ${buildTypeId}; verify the feature ID or update via the TeamCity UI.`
2239
+ );
2240
+ }
2241
+ const payload = this.buildPayload(existing, input);
2242
+ await this.client.modules.buildTypes.replaceBuildFeature(
2243
+ buildTypeId,
2244
+ featureId,
2245
+ void 0,
2246
+ payload,
2247
+ JSON_HEADERS3
2248
+ );
2249
+ return { id: featureId };
2250
+ }
2251
+ async deleteFeature(buildTypeId, featureId) {
2252
+ await this.client.modules.buildTypes.deleteFeatureOfBuildType(
2253
+ buildTypeId,
2254
+ featureId,
2255
+ JSON_HEADERS3
2256
+ );
2257
+ }
2258
+ async fetchFeature(buildTypeId, featureId) {
2259
+ try {
2260
+ const response = await this.client.modules.buildTypes.getBuildFeature(
2261
+ buildTypeId,
2262
+ featureId,
2263
+ "id,type,disabled,properties(property(name,value))",
2264
+ JSON_GET_HEADERS3
2265
+ );
2266
+ return response.data;
2267
+ } catch (error2) {
2268
+ if (typeof error2 === "object" && error2 !== null && "response" in error2 && error2.response?.status === 404) {
2269
+ return null;
2270
+ }
2271
+ throw error2;
2272
+ }
2273
+ }
2274
+ buildPayload(existing, input) {
2275
+ const baseProps = propertiesToRecord3(existing?.properties);
2276
+ const mergedProps = mergeRecords3(baseProps, toStringRecord3(input.properties));
2277
+ const payload = {
2278
+ ...existing ?? {},
2279
+ disabled: input.disabled ?? existing?.disabled
2280
+ };
2281
+ if (existing?.type && !input.type) {
2282
+ payload.type = existing.type;
2283
+ }
2284
+ if (input.type) {
2285
+ payload.type = input.type;
2286
+ }
2287
+ const properties = recordToProperties3(mergedProps);
2288
+ if (properties) {
2289
+ payload.properties = properties;
2290
+ }
2291
+ return payload;
2292
+ }
2293
+ };
2294
+
1820
2295
  // src/teamcity/build-results-manager.ts
1821
2296
  init_errors();
1822
2297
  var isRecord2 = (value) => {
@@ -37781,6 +38256,14 @@ var DEV_TOOLS = [
37781
38256
  type: "object",
37782
38257
  properties: {
37783
38258
  buildId: { type: "string", description: "Build ID" },
38259
+ buildNumber: {
38260
+ type: "string",
38261
+ description: "Human build number (requires buildTypeId when provided)"
38262
+ },
38263
+ buildTypeId: {
38264
+ type: "string",
38265
+ description: "Build configuration identifier (required when using buildNumber)"
38266
+ },
37784
38267
  includeTests: { type: "boolean", description: "Include test summary" },
37785
38268
  includeProblems: { type: "boolean", description: "Include build problems" },
37786
38269
  includeQueueTotals: {
@@ -37791,16 +38274,32 @@ var DEV_TOOLS = [
37791
38274
  type: "boolean",
37792
38275
  description: "Include waitReason for the queued item (extra API call when queued)"
37793
38276
  }
37794
- },
37795
- required: ["buildId"]
38277
+ }
37796
38278
  },
37797
38279
  handler: async (args) => {
37798
38280
  const schema = import_zod4.z.object({
37799
- buildId: import_zod4.z.string().min(1),
38281
+ buildId: import_zod4.z.string().min(1).optional(),
38282
+ buildNumber: import_zod4.z.string().min(1).optional(),
38283
+ buildTypeId: import_zod4.z.string().min(1).optional(),
37800
38284
  includeTests: import_zod4.z.boolean().optional(),
37801
38285
  includeProblems: import_zod4.z.boolean().optional(),
37802
38286
  includeQueueTotals: import_zod4.z.boolean().optional(),
37803
38287
  includeQueueReason: import_zod4.z.boolean().optional()
38288
+ }).superRefine((value, ctx) => {
38289
+ if (!value.buildId && !value.buildNumber) {
38290
+ ctx.addIssue({
38291
+ code: import_zod4.z.ZodIssueCode.custom,
38292
+ path: ["buildId"],
38293
+ message: "Either buildId or buildNumber must be provided"
38294
+ });
38295
+ }
38296
+ if (value.buildNumber && !value.buildTypeId) {
38297
+ ctx.addIssue({
38298
+ code: import_zod4.z.ZodIssueCode.custom,
38299
+ path: ["buildTypeId"],
38300
+ message: "buildTypeId is required when querying by buildNumber"
38301
+ });
38302
+ }
37804
38303
  });
37805
38304
  return runTool(
37806
38305
  "get_build_status",
@@ -37810,6 +38309,8 @@ var DEV_TOOLS = [
37810
38309
  const statusManager = new (await Promise.resolve().then(() => (init_build_status_manager(), build_status_manager_exports))).BuildStatusManager(adapter);
37811
38310
  const result = await statusManager.getBuildStatus({
37812
38311
  buildId: typed.buildId,
38312
+ buildNumber: typed.buildNumber,
38313
+ buildTypeId: typed.buildTypeId,
37813
38314
  includeTests: typed.includeTests,
37814
38315
  includeProblems: typed.includeProblems
37815
38316
  });
@@ -37830,8 +38331,11 @@ var DEV_TOOLS = [
37830
38331
  }
37831
38332
  if (typed.includeQueueReason) {
37832
38333
  try {
37833
- const qb = await adapter.modules.buildQueue.getQueuedBuild(typed.buildId);
37834
- enrich.waitReason = qb.data.waitReason;
38334
+ const targetBuildId = typed.buildId ?? result.buildId;
38335
+ if (targetBuildId) {
38336
+ const qb = await adapter.modules.buildQueue.getQueuedBuild(targetBuildId);
38337
+ enrich.waitReason = qb.data.waitReason;
38338
+ }
37835
38339
  } catch {
37836
38340
  }
37837
38341
  }
@@ -40314,6 +40818,392 @@ var FULL_MODE_TOOLS = [
40314
40818
  },
40315
40819
  mode: "full"
40316
40820
  },
40821
+ // === Dependency, Feature, and Requirement Management ===
40822
+ {
40823
+ name: "manage_build_dependencies",
40824
+ description: "Add, update, or delete artifact and snapshot dependencies for a build configuration",
40825
+ inputSchema: {
40826
+ type: "object",
40827
+ properties: {
40828
+ buildTypeId: { type: "string", description: "Build configuration ID" },
40829
+ dependencyType: {
40830
+ type: "string",
40831
+ enum: ["artifact", "snapshot"],
40832
+ description: "Dependency type to manage"
40833
+ },
40834
+ action: {
40835
+ type: "string",
40836
+ enum: ["add", "update", "delete"],
40837
+ description: "Operation to perform"
40838
+ },
40839
+ dependencyId: {
40840
+ type: "string",
40841
+ description: "Dependency ID (required for update/delete)"
40842
+ },
40843
+ dependsOn: {
40844
+ type: "string",
40845
+ description: "Upstream build configuration ID for the dependency"
40846
+ },
40847
+ properties: {
40848
+ type: "object",
40849
+ description: "Dependency properties (e.g. cleanDestinationDirectory, pathRules)"
40850
+ },
40851
+ type: {
40852
+ type: "string",
40853
+ description: "Override dependency type value sent to TeamCity"
40854
+ },
40855
+ disabled: { type: "boolean", description: "Disable or enable the dependency" }
40856
+ },
40857
+ required: ["buildTypeId", "dependencyType", "action"]
40858
+ },
40859
+ handler: async (args) => {
40860
+ const propertyValue = import_zod4.z.union([import_zod4.z.string(), import_zod4.z.number(), import_zod4.z.boolean()]);
40861
+ const schema = import_zod4.z.object({
40862
+ buildTypeId: import_zod4.z.string().min(1),
40863
+ dependencyType: import_zod4.z.enum(["artifact", "snapshot"]),
40864
+ action: import_zod4.z.enum(["add", "update", "delete"]),
40865
+ dependencyId: import_zod4.z.string().min(1).optional(),
40866
+ dependsOn: import_zod4.z.string().min(1).optional(),
40867
+ properties: import_zod4.z.record(import_zod4.z.string(), propertyValue).optional(),
40868
+ type: import_zod4.z.string().min(1).optional(),
40869
+ disabled: import_zod4.z.boolean().optional()
40870
+ }).superRefine((value, ctx) => {
40871
+ if ((value.action === "update" || value.action === "delete") && !value.dependencyId) {
40872
+ ctx.addIssue({
40873
+ code: import_zod4.z.ZodIssueCode.custom,
40874
+ message: "dependencyId is required for update/delete actions. Provide the TeamCity dependency ID or fall back to the UI.",
40875
+ path: ["dependencyId"]
40876
+ });
40877
+ }
40878
+ if (value.action === "add" && !value.dependsOn) {
40879
+ ctx.addIssue({
40880
+ code: import_zod4.z.ZodIssueCode.custom,
40881
+ message: "dependsOn is required when adding a dependency.",
40882
+ path: ["dependsOn"]
40883
+ });
40884
+ }
40885
+ });
40886
+ return runTool(
40887
+ "manage_build_dependencies",
40888
+ schema,
40889
+ async (typed) => {
40890
+ const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
40891
+ const manager = new BuildDependencyManager(adapter);
40892
+ switch (typed.action) {
40893
+ case "add": {
40894
+ const result = await manager.addDependency({
40895
+ buildTypeId: typed.buildTypeId,
40896
+ dependencyType: typed.dependencyType,
40897
+ dependsOn: typed.dependsOn,
40898
+ properties: typed.properties,
40899
+ type: typed.type,
40900
+ disabled: typed.disabled
40901
+ });
40902
+ return json({
40903
+ success: true,
40904
+ action: "manage_build_dependencies",
40905
+ operation: "add",
40906
+ buildTypeId: typed.buildTypeId,
40907
+ dependencyType: typed.dependencyType,
40908
+ dependencyId: result.id
40909
+ });
40910
+ }
40911
+ case "update": {
40912
+ const result = await manager.updateDependency(typed.dependencyId, {
40913
+ buildTypeId: typed.buildTypeId,
40914
+ dependencyType: typed.dependencyType,
40915
+ dependsOn: typed.dependsOn,
40916
+ properties: typed.properties,
40917
+ type: typed.type,
40918
+ disabled: typed.disabled
40919
+ });
40920
+ return json({
40921
+ success: true,
40922
+ action: "manage_build_dependencies",
40923
+ operation: "update",
40924
+ buildTypeId: typed.buildTypeId,
40925
+ dependencyType: typed.dependencyType,
40926
+ dependencyId: result.id
40927
+ });
40928
+ }
40929
+ case "delete": {
40930
+ await manager.deleteDependency(
40931
+ typed.dependencyType,
40932
+ typed.buildTypeId,
40933
+ typed.dependencyId
40934
+ );
40935
+ return json({
40936
+ success: true,
40937
+ action: "manage_build_dependencies",
40938
+ operation: "delete",
40939
+ buildTypeId: typed.buildTypeId,
40940
+ dependencyType: typed.dependencyType,
40941
+ dependencyId: typed.dependencyId
40942
+ });
40943
+ }
40944
+ default:
40945
+ return json({
40946
+ success: false,
40947
+ action: "manage_build_dependencies",
40948
+ error: `Unsupported action: ${typed.action}`
40949
+ });
40950
+ }
40951
+ },
40952
+ args
40953
+ );
40954
+ },
40955
+ mode: "full"
40956
+ },
40957
+ {
40958
+ name: "manage_build_features",
40959
+ description: "Add, update, or delete build features such as ssh-agent or requirements enforcement",
40960
+ inputSchema: {
40961
+ type: "object",
40962
+ properties: {
40963
+ buildTypeId: { type: "string", description: "Build configuration ID" },
40964
+ action: {
40965
+ type: "string",
40966
+ enum: ["add", "update", "delete"],
40967
+ description: "Operation to perform"
40968
+ },
40969
+ featureId: {
40970
+ type: "string",
40971
+ description: "Feature ID (required for update/delete)"
40972
+ },
40973
+ type: { type: "string", description: "Feature type (required for add)" },
40974
+ properties: { type: "object", description: "Feature properties" },
40975
+ disabled: { type: "boolean", description: "Disable or enable the feature" }
40976
+ },
40977
+ required: ["buildTypeId", "action"]
40978
+ },
40979
+ handler: async (args) => {
40980
+ const propertyValue = import_zod4.z.union([import_zod4.z.string(), import_zod4.z.number(), import_zod4.z.boolean()]);
40981
+ const schema = import_zod4.z.object({
40982
+ buildTypeId: import_zod4.z.string().min(1),
40983
+ action: import_zod4.z.enum(["add", "update", "delete"]),
40984
+ featureId: import_zod4.z.string().min(1).optional(),
40985
+ type: import_zod4.z.string().min(1).optional(),
40986
+ properties: import_zod4.z.record(import_zod4.z.string(), propertyValue).optional(),
40987
+ disabled: import_zod4.z.boolean().optional()
40988
+ }).superRefine((value, ctx) => {
40989
+ if ((value.action === "update" || value.action === "delete") && !value.featureId) {
40990
+ ctx.addIssue({
40991
+ code: import_zod4.z.ZodIssueCode.custom,
40992
+ message: "featureId is required for update/delete actions. Capture the feature ID from TeamCity or use the UI.",
40993
+ path: ["featureId"]
40994
+ });
40995
+ }
40996
+ if (value.action === "add" && !value.type) {
40997
+ ctx.addIssue({
40998
+ code: import_zod4.z.ZodIssueCode.custom,
40999
+ message: "type is required when adding a build feature.",
41000
+ path: ["type"]
41001
+ });
41002
+ }
41003
+ });
41004
+ return runTool(
41005
+ "manage_build_features",
41006
+ schema,
41007
+ async (typed) => {
41008
+ const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
41009
+ const manager = new BuildFeatureManager(adapter);
41010
+ switch (typed.action) {
41011
+ case "add": {
41012
+ const result = await manager.addFeature({
41013
+ buildTypeId: typed.buildTypeId,
41014
+ type: typed.type,
41015
+ properties: typed.properties,
41016
+ disabled: typed.disabled
41017
+ });
41018
+ return json({
41019
+ success: true,
41020
+ action: "manage_build_features",
41021
+ operation: "add",
41022
+ buildTypeId: typed.buildTypeId,
41023
+ featureId: result.id
41024
+ });
41025
+ }
41026
+ case "update": {
41027
+ const result = await manager.updateFeature(typed.featureId, {
41028
+ buildTypeId: typed.buildTypeId,
41029
+ type: typed.type,
41030
+ properties: typed.properties,
41031
+ disabled: typed.disabled
41032
+ });
41033
+ return json({
41034
+ success: true,
41035
+ action: "manage_build_features",
41036
+ operation: "update",
41037
+ buildTypeId: typed.buildTypeId,
41038
+ featureId: result.id
41039
+ });
41040
+ }
41041
+ case "delete": {
41042
+ await manager.deleteFeature(typed.buildTypeId, typed.featureId);
41043
+ return json({
41044
+ success: true,
41045
+ action: "manage_build_features",
41046
+ operation: "delete",
41047
+ buildTypeId: typed.buildTypeId,
41048
+ featureId: typed.featureId
41049
+ });
41050
+ }
41051
+ default:
41052
+ return json({
41053
+ success: false,
41054
+ action: "manage_build_features",
41055
+ error: `Unsupported action: ${typed.action}`
41056
+ });
41057
+ }
41058
+ },
41059
+ args
41060
+ );
41061
+ },
41062
+ mode: "full"
41063
+ },
41064
+ {
41065
+ name: "manage_agent_requirements",
41066
+ description: "Add, update, or delete build agent requirements for a configuration",
41067
+ inputSchema: {
41068
+ type: "object",
41069
+ properties: {
41070
+ buildTypeId: { type: "string", description: "Build configuration ID" },
41071
+ action: {
41072
+ type: "string",
41073
+ enum: ["add", "update", "delete"],
41074
+ description: "Operation to perform"
41075
+ },
41076
+ requirementId: {
41077
+ type: "string",
41078
+ description: "Requirement ID (required for update/delete)"
41079
+ },
41080
+ properties: {
41081
+ type: "object",
41082
+ description: "Requirement properties (e.g. property-name, condition, value)"
41083
+ },
41084
+ disabled: { type: "boolean", description: "Disable or enable the requirement" }
41085
+ },
41086
+ required: ["buildTypeId", "action"]
41087
+ },
41088
+ handler: async (args) => {
41089
+ const propertyValue = import_zod4.z.union([import_zod4.z.string(), import_zod4.z.number(), import_zod4.z.boolean()]);
41090
+ const schema = import_zod4.z.object({
41091
+ buildTypeId: import_zod4.z.string().min(1),
41092
+ action: import_zod4.z.enum(["add", "update", "delete"]),
41093
+ requirementId: import_zod4.z.string().min(1).optional(),
41094
+ properties: import_zod4.z.record(import_zod4.z.string(), propertyValue).optional(),
41095
+ disabled: import_zod4.z.boolean().optional()
41096
+ }).superRefine((value, ctx) => {
41097
+ if ((value.action === "update" || value.action === "delete") && !value.requirementId) {
41098
+ ctx.addIssue({
41099
+ code: import_zod4.z.ZodIssueCode.custom,
41100
+ message: "requirementId is required for update/delete actions. Capture the requirement ID via the API or TeamCity UI.",
41101
+ path: ["requirementId"]
41102
+ });
41103
+ }
41104
+ });
41105
+ return runTool(
41106
+ "manage_agent_requirements",
41107
+ schema,
41108
+ async (typed) => {
41109
+ const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
41110
+ const manager = new AgentRequirementsManager(adapter);
41111
+ switch (typed.action) {
41112
+ case "add": {
41113
+ const result = await manager.addRequirement({
41114
+ buildTypeId: typed.buildTypeId,
41115
+ properties: typed.properties,
41116
+ disabled: typed.disabled
41117
+ });
41118
+ return json({
41119
+ success: true,
41120
+ action: "manage_agent_requirements",
41121
+ operation: "add",
41122
+ buildTypeId: typed.buildTypeId,
41123
+ requirementId: result.id
41124
+ });
41125
+ }
41126
+ case "update": {
41127
+ const result = await manager.updateRequirement(typed.requirementId, {
41128
+ buildTypeId: typed.buildTypeId,
41129
+ properties: typed.properties,
41130
+ disabled: typed.disabled
41131
+ });
41132
+ return json({
41133
+ success: true,
41134
+ action: "manage_agent_requirements",
41135
+ operation: "update",
41136
+ buildTypeId: typed.buildTypeId,
41137
+ requirementId: result.id
41138
+ });
41139
+ }
41140
+ case "delete": {
41141
+ await manager.deleteRequirement(typed.buildTypeId, typed.requirementId);
41142
+ return json({
41143
+ success: true,
41144
+ action: "manage_agent_requirements",
41145
+ operation: "delete",
41146
+ buildTypeId: typed.buildTypeId,
41147
+ requirementId: typed.requirementId
41148
+ });
41149
+ }
41150
+ default:
41151
+ return json({
41152
+ success: false,
41153
+ action: "manage_agent_requirements",
41154
+ error: `Unsupported action: ${typed.action}`
41155
+ });
41156
+ }
41157
+ },
41158
+ args
41159
+ );
41160
+ },
41161
+ mode: "full"
41162
+ },
41163
+ {
41164
+ name: "set_build_config_state",
41165
+ description: "Enable or disable a build configuration by toggling its paused flag",
41166
+ inputSchema: {
41167
+ type: "object",
41168
+ properties: {
41169
+ buildTypeId: { type: "string", description: "Build configuration ID" },
41170
+ paused: { type: "boolean", description: "True to pause/disable, false to enable" }
41171
+ },
41172
+ required: ["buildTypeId", "paused"]
41173
+ },
41174
+ handler: async (args) => {
41175
+ const schema = import_zod4.z.object({
41176
+ buildTypeId: import_zod4.z.string().min(1),
41177
+ paused: import_zod4.z.boolean()
41178
+ });
41179
+ return runTool(
41180
+ "set_build_config_state",
41181
+ schema,
41182
+ async (typed) => {
41183
+ const adapter = createAdapterFromTeamCityAPI(TeamCityAPI.getInstance());
41184
+ await adapter.modules.buildTypes.setBuildTypeField(
41185
+ typed.buildTypeId,
41186
+ "paused",
41187
+ String(typed.paused),
41188
+ {
41189
+ headers: {
41190
+ "Content-Type": "text/plain",
41191
+ Accept: "application/json"
41192
+ }
41193
+ }
41194
+ );
41195
+ return json({
41196
+ success: true,
41197
+ action: "set_build_config_state",
41198
+ buildTypeId: typed.buildTypeId,
41199
+ paused: typed.paused
41200
+ });
41201
+ },
41202
+ args
41203
+ );
41204
+ },
41205
+ mode: "full"
41206
+ },
40317
41207
  // === VCS attachment ===
40318
41208
  {
40319
41209
  name: "add_vcs_root_to_build",