@cyanheads/git-mcp-server 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -38
- package/dist/index.js +1855 -2035
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15284,7 +15284,7 @@ var package_default;
|
|
|
15284
15284
|
var init_package = __esm(() => {
|
|
15285
15285
|
package_default = {
|
|
15286
15286
|
name: "@cyanheads/git-mcp-server",
|
|
15287
|
-
version: "2.
|
|
15287
|
+
version: "2.13.0",
|
|
15288
15288
|
mcpName: "io.github.cyanheads/git-mcp-server",
|
|
15289
15289
|
description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
|
|
15290
15290
|
main: "dist/index.js",
|
|
@@ -15517,6 +15517,17 @@ var import_dotenv, packageManifest, emptyStringAsUndefined = (val) => {
|
|
|
15517
15517
|
return;
|
|
15518
15518
|
}
|
|
15519
15519
|
return val;
|
|
15520
|
+
}, parseBoolEnv = (defaultValue) => (val) => {
|
|
15521
|
+
if (typeof val === "boolean")
|
|
15522
|
+
return val;
|
|
15523
|
+
if (typeof val === "string") {
|
|
15524
|
+
const lower = val.trim().toLowerCase();
|
|
15525
|
+
if (["true", "1", "yes", "on"].includes(lower))
|
|
15526
|
+
return true;
|
|
15527
|
+
if (["false", "0", "no", "off", ""].includes(lower))
|
|
15528
|
+
return false;
|
|
15529
|
+
}
|
|
15530
|
+
return defaultValue;
|
|
15520
15531
|
}, expandTildePath = (path2) => {
|
|
15521
15532
|
if (typeof path2 !== "string" || path2.trim() === "") {
|
|
15522
15533
|
return;
|
|
@@ -15737,7 +15748,7 @@ var init_config = __esm(() => {
|
|
|
15737
15748
|
}),
|
|
15738
15749
|
git: exports_external.object({
|
|
15739
15750
|
provider: exports_external.preprocess(emptyStringAsUndefined, exports_external.enum(["auto", "cli", "isomorphic"]).default("auto")),
|
|
15740
|
-
signCommits: exports_external.
|
|
15751
|
+
signCommits: exports_external.preprocess(parseBoolEnv(true), exports_external.boolean()),
|
|
15741
15752
|
authorName: exports_external.string().regex(/^[^\n\r\0]*$/, "Git author name must not contain newlines or null bytes").optional(),
|
|
15742
15753
|
authorEmail: exports_external.string().email().optional(),
|
|
15743
15754
|
committerName: exports_external.string().regex(/^[^\n\r\0]*$/, "Git committer name must not contain newlines or null bytes").optional(),
|
|
@@ -105568,75 +105579,6 @@ var require_index_incubating = __commonJS((exports) => {
|
|
|
105568
105579
|
__exportStar(require_experimental_events(), exports);
|
|
105569
105580
|
});
|
|
105570
105581
|
|
|
105571
|
-
// src/mcp-server/transports/auth/lib/authContext.ts
|
|
105572
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
105573
|
-
var authContext;
|
|
105574
|
-
var init_authContext = __esm(() => {
|
|
105575
|
-
authContext = new AsyncLocalStorage;
|
|
105576
|
-
});
|
|
105577
|
-
|
|
105578
|
-
// src/utils/internal/requestContext.ts
|
|
105579
|
-
var import_api2, requestContextServiceInstance, requestContextService;
|
|
105580
|
-
var init_requestContext = __esm(() => {
|
|
105581
|
-
init_authContext();
|
|
105582
|
-
init_utils();
|
|
105583
|
-
init_logger();
|
|
105584
|
-
import_api2 = __toESM(require_src(), 1);
|
|
105585
|
-
requestContextServiceInstance = {
|
|
105586
|
-
config: {},
|
|
105587
|
-
configure(config3) {
|
|
105588
|
-
this.config = {
|
|
105589
|
-
...this.config,
|
|
105590
|
-
...config3
|
|
105591
|
-
};
|
|
105592
|
-
const logContext = this.createRequestContext({
|
|
105593
|
-
operation: "RequestContextService.configure",
|
|
105594
|
-
additionalContext: { newConfigState: { ...this.config } }
|
|
105595
|
-
});
|
|
105596
|
-
logger.debug("RequestContextService configuration updated", logContext);
|
|
105597
|
-
return { ...this.config };
|
|
105598
|
-
},
|
|
105599
|
-
getConfig() {
|
|
105600
|
-
return { ...this.config };
|
|
105601
|
-
},
|
|
105602
|
-
createRequestContext(params = {}) {
|
|
105603
|
-
const { parentContext, additionalContext, operation, ...rest } = params;
|
|
105604
|
-
const inheritedContext = parentContext && typeof parentContext === "object" ? { ...parentContext } : {};
|
|
105605
|
-
let inheritedTenantId;
|
|
105606
|
-
if (inheritedContext && typeof inheritedContext === "object" && "tenantId" in inheritedContext && typeof inheritedContext.tenantId === "string") {
|
|
105607
|
-
inheritedTenantId = inheritedContext.tenantId;
|
|
105608
|
-
}
|
|
105609
|
-
const authStore = authContext.getStore();
|
|
105610
|
-
const tenantIdFromAuth = authStore?.authInfo?.tenantId;
|
|
105611
|
-
const inheritedRequestId = inheritedContext.requestId;
|
|
105612
|
-
const requestId = typeof inheritedRequestId === "string" && inheritedRequestId ? inheritedRequestId : generateRequestContextId();
|
|
105613
|
-
const timestamp = new Date().toISOString();
|
|
105614
|
-
const restTenantId = typeof rest.tenantId === "string" ? rest.tenantId : undefined;
|
|
105615
|
-
const additionalTenantId = additionalContext && typeof additionalContext === "object" && typeof additionalContext.tenantId === "string" ? additionalContext.tenantId : undefined;
|
|
105616
|
-
const resolvedTenantId = additionalTenantId ?? restTenantId ?? inheritedTenantId ?? tenantIdFromAuth;
|
|
105617
|
-
const context = {
|
|
105618
|
-
...inheritedContext,
|
|
105619
|
-
...rest,
|
|
105620
|
-
requestId,
|
|
105621
|
-
timestamp,
|
|
105622
|
-
...resolvedTenantId ? { tenantId: resolvedTenantId } : {},
|
|
105623
|
-
...additionalContext && typeof additionalContext === "object" ? additionalContext : {},
|
|
105624
|
-
...operation && typeof operation === "string" ? { operation } : {}
|
|
105625
|
-
};
|
|
105626
|
-
const activeSpan = import_api2.trace.getActiveSpan();
|
|
105627
|
-
if (activeSpan && typeof activeSpan.spanContext === "function") {
|
|
105628
|
-
const spanContext = activeSpan.spanContext();
|
|
105629
|
-
if (spanContext) {
|
|
105630
|
-
context.traceId = spanContext.traceId;
|
|
105631
|
-
context.spanId = spanContext.spanId;
|
|
105632
|
-
}
|
|
105633
|
-
}
|
|
105634
|
-
return context;
|
|
105635
|
-
}
|
|
105636
|
-
};
|
|
105637
|
-
requestContextService = requestContextServiceInstance;
|
|
105638
|
-
});
|
|
105639
|
-
|
|
105640
105582
|
// node_modules/validator/lib/util/assertString.js
|
|
105641
105583
|
var require_assertString = __commonJS((exports, module) => {
|
|
105642
105584
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -112035,1408 +111977,6 @@ var require_validator = __commonJS((exports, module) => {
|
|
|
112035
111977
|
module.exports.default = exports.default;
|
|
112036
111978
|
});
|
|
112037
111979
|
|
|
112038
|
-
// src/utils/security/sanitization.ts
|
|
112039
|
-
class Sanitization {
|
|
112040
|
-
static instance;
|
|
112041
|
-
sensitiveFields = [
|
|
112042
|
-
"password",
|
|
112043
|
-
"token",
|
|
112044
|
-
"secret",
|
|
112045
|
-
"apiKey",
|
|
112046
|
-
"credential",
|
|
112047
|
-
"jwt",
|
|
112048
|
-
"ssn",
|
|
112049
|
-
"cvv",
|
|
112050
|
-
"authorization",
|
|
112051
|
-
"cookie",
|
|
112052
|
-
"clientsecret",
|
|
112053
|
-
"client_secret",
|
|
112054
|
-
"private_key",
|
|
112055
|
-
"privatekey"
|
|
112056
|
-
];
|
|
112057
|
-
constructor() {}
|
|
112058
|
-
static getInstance() {
|
|
112059
|
-
if (!Sanitization.instance) {
|
|
112060
|
-
Sanitization.instance = new Sanitization;
|
|
112061
|
-
}
|
|
112062
|
-
return Sanitization.instance;
|
|
112063
|
-
}
|
|
112064
|
-
setSensitiveFields(fields) {
|
|
112065
|
-
this.sensitiveFields = [
|
|
112066
|
-
...new Set([
|
|
112067
|
-
...this.sensitiveFields,
|
|
112068
|
-
...fields.map((f3) => f3.toLowerCase())
|
|
112069
|
-
])
|
|
112070
|
-
];
|
|
112071
|
-
const logContext = requestContextService.createRequestContext({
|
|
112072
|
-
operation: "Sanitization.setSensitiveFields",
|
|
112073
|
-
additionalContext: {
|
|
112074
|
-
newSensitiveFieldCount: this.sensitiveFields.length
|
|
112075
|
-
}
|
|
112076
|
-
});
|
|
112077
|
-
logger.debug("Updated sensitive fields list for log sanitization", logContext);
|
|
112078
|
-
}
|
|
112079
|
-
getSensitiveFields() {
|
|
112080
|
-
return [...this.sensitiveFields];
|
|
112081
|
-
}
|
|
112082
|
-
getSensitivePinoFields() {
|
|
112083
|
-
return this.sensitiveFields.map((field) => field.replace(/[-_]/g, ""));
|
|
112084
|
-
}
|
|
112085
|
-
sanitizeUrl(input, allowedProtocols = ["http", "https"]) {
|
|
112086
|
-
try {
|
|
112087
|
-
const trimmedInput = input.trim();
|
|
112088
|
-
if (!import_validator.default.isURL(trimmedInput, {
|
|
112089
|
-
protocols: allowedProtocols,
|
|
112090
|
-
require_protocol: true,
|
|
112091
|
-
require_host: true
|
|
112092
|
-
})) {
|
|
112093
|
-
throw new Error("Invalid URL format or protocol not in allowed list.");
|
|
112094
|
-
}
|
|
112095
|
-
const lowercasedInput = trimmedInput.toLowerCase();
|
|
112096
|
-
if (lowercasedInput.startsWith("javascript:") || lowercasedInput.startsWith("data:") || lowercasedInput.startsWith("vbscript:")) {
|
|
112097
|
-
throw new Error("Disallowed pseudo-protocol (javascript:, data:, or vbscript:) in URL.");
|
|
112098
|
-
}
|
|
112099
|
-
return trimmedInput;
|
|
112100
|
-
} catch (error48) {
|
|
112101
|
-
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid or unsafe URL provided.", { input });
|
|
112102
|
-
}
|
|
112103
|
-
}
|
|
112104
|
-
sanitizePath(input, options = {}) {
|
|
112105
|
-
if (isServerless || !pathModule) {
|
|
112106
|
-
throw new McpError(-32603 /* InternalError */, "File-based path sanitization is not supported in this environment.");
|
|
112107
|
-
}
|
|
112108
|
-
const path2 = pathModule;
|
|
112109
|
-
const originalInput = input;
|
|
112110
|
-
const resolvedRootDir = options.rootDir ? path2.resolve(options.rootDir) : undefined;
|
|
112111
|
-
const effectiveOptions = {
|
|
112112
|
-
toPosix: options.toPosix ?? false,
|
|
112113
|
-
allowAbsolute: options.allowAbsolute ?? false,
|
|
112114
|
-
...resolvedRootDir && { rootDir: resolvedRootDir }
|
|
112115
|
-
};
|
|
112116
|
-
let wasAbsoluteInitially = false;
|
|
112117
|
-
try {
|
|
112118
|
-
if (!input || typeof input !== "string")
|
|
112119
|
-
throw new Error("Invalid path input: must be a non-empty string.");
|
|
112120
|
-
if (input.includes("\x00"))
|
|
112121
|
-
throw new Error("Path contains null byte, which is disallowed.");
|
|
112122
|
-
let normalized = path2.normalize(input);
|
|
112123
|
-
wasAbsoluteInitially = path2.isAbsolute(normalized);
|
|
112124
|
-
if (effectiveOptions.toPosix) {
|
|
112125
|
-
normalized = normalized.replace(/\\/g, "/");
|
|
112126
|
-
}
|
|
112127
|
-
let finalSanitizedPath;
|
|
112128
|
-
if (resolvedRootDir) {
|
|
112129
|
-
let fullPath;
|
|
112130
|
-
if (path2.isAbsolute(normalized)) {
|
|
112131
|
-
fullPath = path2.normalize(normalized);
|
|
112132
|
-
} else {
|
|
112133
|
-
fullPath = path2.resolve(resolvedRootDir, normalized);
|
|
112134
|
-
}
|
|
112135
|
-
const normalizedRoot = path2.normalize(resolvedRootDir);
|
|
112136
|
-
const normalizedFull = path2.normalize(fullPath);
|
|
112137
|
-
if (!normalizedFull.startsWith(normalizedRoot + path2.sep) && normalizedFull !== normalizedRoot) {
|
|
112138
|
-
throw new Error("Path traversal detected: attempts to escape the defined root directory.");
|
|
112139
|
-
}
|
|
112140
|
-
finalSanitizedPath = path2.relative(normalizedRoot, normalizedFull);
|
|
112141
|
-
finalSanitizedPath = finalSanitizedPath === "" ? "." : finalSanitizedPath;
|
|
112142
|
-
if (path2.isAbsolute(finalSanitizedPath) && !effectiveOptions.allowAbsolute) {
|
|
112143
|
-
throw new Error("Path resolved to absolute outside root when absolute paths are disallowed.");
|
|
112144
|
-
}
|
|
112145
|
-
} else {
|
|
112146
|
-
if (path2.isAbsolute(normalized)) {
|
|
112147
|
-
if (!effectiveOptions.allowAbsolute) {
|
|
112148
|
-
throw new Error("Absolute paths are disallowed by current options.");
|
|
112149
|
-
} else {
|
|
112150
|
-
finalSanitizedPath = normalized;
|
|
112151
|
-
}
|
|
112152
|
-
} else {
|
|
112153
|
-
const resolvedAgainstCwd = path2.resolve(normalized);
|
|
112154
|
-
const currentWorkingDir = path2.resolve(".");
|
|
112155
|
-
if (!resolvedAgainstCwd.startsWith(currentWorkingDir + path2.sep) && resolvedAgainstCwd !== currentWorkingDir) {
|
|
112156
|
-
throw new Error("Relative path traversal detected (escapes current working directory context).");
|
|
112157
|
-
}
|
|
112158
|
-
finalSanitizedPath = normalized;
|
|
112159
|
-
}
|
|
112160
|
-
}
|
|
112161
|
-
return {
|
|
112162
|
-
sanitizedPath: finalSanitizedPath,
|
|
112163
|
-
originalInput,
|
|
112164
|
-
wasAbsolute: wasAbsoluteInitially,
|
|
112165
|
-
convertedToRelative: wasAbsoluteInitially && !path2.isAbsolute(finalSanitizedPath) && !effectiveOptions.allowAbsolute,
|
|
112166
|
-
optionsUsed: effectiveOptions
|
|
112167
|
-
};
|
|
112168
|
-
} catch (error48) {
|
|
112169
|
-
logger.warning("Path sanitization error", requestContextService.createRequestContext({
|
|
112170
|
-
operation: "Sanitization.sanitizePath.error",
|
|
112171
|
-
additionalContext: {
|
|
112172
|
-
originalPathInput: originalInput,
|
|
112173
|
-
pathOptionsUsed: effectiveOptions,
|
|
112174
|
-
errorMessage: error48 instanceof Error ? error48.message : String(error48)
|
|
112175
|
-
}
|
|
112176
|
-
}));
|
|
112177
|
-
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid or unsafe path provided.", { input: originalInput });
|
|
112178
|
-
}
|
|
112179
|
-
}
|
|
112180
|
-
sanitizeJson(input, maxSize) {
|
|
112181
|
-
try {
|
|
112182
|
-
if (typeof input !== "string")
|
|
112183
|
-
throw new Error("Invalid input: expected a JSON string.");
|
|
112184
|
-
const computeBytes = (s2) => {
|
|
112185
|
-
if (typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function") {
|
|
112186
|
-
return Buffer.byteLength(s2, "utf8");
|
|
112187
|
-
}
|
|
112188
|
-
if (typeof TextEncoder !== "undefined") {
|
|
112189
|
-
return new TextEncoder().encode(s2).length;
|
|
112190
|
-
}
|
|
112191
|
-
return s2.length;
|
|
112192
|
-
};
|
|
112193
|
-
if (maxSize !== undefined && computeBytes(input) > maxSize) {
|
|
112194
|
-
throw new McpError(-32007 /* ValidationError */, `JSON string exceeds maximum allowed size of ${maxSize} bytes.`, { actualSize: computeBytes(input), maxSize });
|
|
112195
|
-
}
|
|
112196
|
-
return JSON.parse(input);
|
|
112197
|
-
} catch (error48) {
|
|
112198
|
-
if (error48 instanceof McpError)
|
|
112199
|
-
throw error48;
|
|
112200
|
-
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid JSON format.", {
|
|
112201
|
-
inputPreview: input.length > 100 ? `${input.substring(0, 100)}...` : input
|
|
112202
|
-
});
|
|
112203
|
-
}
|
|
112204
|
-
}
|
|
112205
|
-
sanitizeNumber(input, min, max) {
|
|
112206
|
-
let value;
|
|
112207
|
-
if (typeof input === "string") {
|
|
112208
|
-
const trimmedInput = input.trim();
|
|
112209
|
-
if (trimmedInput === "" || !import_validator.default.isNumeric(trimmedInput)) {
|
|
112210
|
-
throw new McpError(-32007 /* ValidationError */, "Invalid number format: input is empty or not numeric.", { input });
|
|
112211
|
-
}
|
|
112212
|
-
value = parseFloat(trimmedInput);
|
|
112213
|
-
} else if (typeof input === "number") {
|
|
112214
|
-
value = input;
|
|
112215
|
-
} else {
|
|
112216
|
-
throw new McpError(-32007 /* ValidationError */, "Invalid input type: expected number or string.", { input: String(input) });
|
|
112217
|
-
}
|
|
112218
|
-
if (isNaN(value) || !isFinite(value)) {
|
|
112219
|
-
throw new McpError(-32007 /* ValidationError */, "Invalid number value (NaN or Infinity).", { input });
|
|
112220
|
-
}
|
|
112221
|
-
let clamped = false;
|
|
112222
|
-
const originalValueForLog = value;
|
|
112223
|
-
if (min !== undefined && value < min) {
|
|
112224
|
-
value = min;
|
|
112225
|
-
clamped = true;
|
|
112226
|
-
}
|
|
112227
|
-
if (max !== undefined && value > max) {
|
|
112228
|
-
value = max;
|
|
112229
|
-
clamped = true;
|
|
112230
|
-
}
|
|
112231
|
-
if (clamped) {
|
|
112232
|
-
logger.debug("Number clamped to range.", requestContextService.createRequestContext({
|
|
112233
|
-
operation: "Sanitization.sanitizeNumber.clamped",
|
|
112234
|
-
additionalContext: {
|
|
112235
|
-
originalInput: String(input),
|
|
112236
|
-
parsedValue: originalValueForLog,
|
|
112237
|
-
minValue: min,
|
|
112238
|
-
maxValue: max,
|
|
112239
|
-
clampedValue: value
|
|
112240
|
-
}
|
|
112241
|
-
}));
|
|
112242
|
-
}
|
|
112243
|
-
return value;
|
|
112244
|
-
}
|
|
112245
|
-
sanitizeForLogging(input) {
|
|
112246
|
-
try {
|
|
112247
|
-
if (!input || typeof input !== "object")
|
|
112248
|
-
return input;
|
|
112249
|
-
const clonedInput = typeof globalThis.structuredClone === "function" ? globalThis.structuredClone(input) : JSON.parse(JSON.stringify(input));
|
|
112250
|
-
this.redactSensitiveFields(clonedInput);
|
|
112251
|
-
return clonedInput;
|
|
112252
|
-
} catch (error48) {
|
|
112253
|
-
logger.error("Error during log sanitization, returning placeholder.", requestContextService.createRequestContext({
|
|
112254
|
-
operation: "Sanitization.sanitizeForLogging.error",
|
|
112255
|
-
additionalContext: {
|
|
112256
|
-
errorMessage: error48 instanceof Error ? error48.message : String(error48)
|
|
112257
|
-
}
|
|
112258
|
-
}));
|
|
112259
|
-
return "[Log Sanitization Failed]";
|
|
112260
|
-
}
|
|
112261
|
-
}
|
|
112262
|
-
redactSensitiveFields(obj) {
|
|
112263
|
-
if (!obj || typeof obj !== "object")
|
|
112264
|
-
return;
|
|
112265
|
-
if (Array.isArray(obj)) {
|
|
112266
|
-
obj.forEach((item) => this.redactSensitiveFields(item));
|
|
112267
|
-
return;
|
|
112268
|
-
}
|
|
112269
|
-
const normalize = (str) => str.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
112270
|
-
const normalizedSensitiveSet = new Set(this.sensitiveFields.map((f3) => normalize(f3)).filter(Boolean));
|
|
112271
|
-
const wordSensitiveSet = new Set(this.sensitiveFields.map((f3) => f3.toLowerCase()).filter(Boolean));
|
|
112272
|
-
for (const key in obj) {
|
|
112273
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
112274
|
-
const value = obj[key];
|
|
112275
|
-
const normalizedKey = normalize(key);
|
|
112276
|
-
const keyWords = key.replace(/([A-Z])/g, " $1").toLowerCase().split(/[\s_-]+/).filter(Boolean);
|
|
112277
|
-
const isExactSensitive = normalizedSensitiveSet.has(normalizedKey);
|
|
112278
|
-
const isWordSensitive = keyWords.some((w) => wordSensitiveSet.has(w));
|
|
112279
|
-
const isSensitive = isExactSensitive || isWordSensitive;
|
|
112280
|
-
if (isSensitive) {
|
|
112281
|
-
obj[key] = "[REDACTED]";
|
|
112282
|
-
} else if (value && typeof value === "object") {
|
|
112283
|
-
this.redactSensitiveFields(value);
|
|
112284
|
-
}
|
|
112285
|
-
}
|
|
112286
|
-
}
|
|
112287
|
-
}
|
|
112288
|
-
}
|
|
112289
|
-
var import_validator, isServerless, pathModule, sanitization, sanitizeInputForLogging = (input) => sanitization.sanitizeForLogging(input);
|
|
112290
|
-
var init_sanitization = __esm(() => {
|
|
112291
|
-
init_errors3();
|
|
112292
|
-
init_utils();
|
|
112293
|
-
import_validator = __toESM(require_validator(), 1);
|
|
112294
|
-
isServerless = typeof process === "undefined" || process.env.IS_SERVERLESS === "true";
|
|
112295
|
-
if (!isServerless) {
|
|
112296
|
-
import("path").then((mod2) => {
|
|
112297
|
-
pathModule = mod2.default;
|
|
112298
|
-
}).catch(() => {});
|
|
112299
|
-
}
|
|
112300
|
-
sanitization = Sanitization.getInstance();
|
|
112301
|
-
});
|
|
112302
|
-
|
|
112303
|
-
// src/utils/internal/logger.ts
|
|
112304
|
-
import pino from "pino";
|
|
112305
|
-
var mcpToPinoLevel, pinoToMcpLevelSeverity, isServerless2, Logger, logger;
|
|
112306
|
-
var init_logger = __esm(() => {
|
|
112307
|
-
init_config();
|
|
112308
|
-
init_requestContext();
|
|
112309
|
-
init_sanitization();
|
|
112310
|
-
mcpToPinoLevel = {
|
|
112311
|
-
emerg: "fatal",
|
|
112312
|
-
alert: "fatal",
|
|
112313
|
-
crit: "error",
|
|
112314
|
-
error: "error",
|
|
112315
|
-
warning: "warn",
|
|
112316
|
-
notice: "info",
|
|
112317
|
-
info: "info",
|
|
112318
|
-
debug: "debug"
|
|
112319
|
-
};
|
|
112320
|
-
pinoToMcpLevelSeverity = {
|
|
112321
|
-
fatal: 0,
|
|
112322
|
-
error: 2,
|
|
112323
|
-
warn: 4,
|
|
112324
|
-
info: 6,
|
|
112325
|
-
debug: 7
|
|
112326
|
-
};
|
|
112327
|
-
isServerless2 = typeof process === "undefined" || process.env.IS_SERVERLESS === "true";
|
|
112328
|
-
Logger = class Logger {
|
|
112329
|
-
static instance = new Logger;
|
|
112330
|
-
pinoLogger;
|
|
112331
|
-
interactionLogger;
|
|
112332
|
-
initialized = false;
|
|
112333
|
-
currentMcpLevel = "info";
|
|
112334
|
-
transportType;
|
|
112335
|
-
rateLimitThreshold = 10;
|
|
112336
|
-
rateLimitWindow = 60000;
|
|
112337
|
-
messageCounts = new Map;
|
|
112338
|
-
suppressedMessages = new Map;
|
|
112339
|
-
cleanupTimer;
|
|
112340
|
-
constructor() {}
|
|
112341
|
-
static getInstance() {
|
|
112342
|
-
return Logger.instance;
|
|
112343
|
-
}
|
|
112344
|
-
async createPinoLogger(level, transportType) {
|
|
112345
|
-
const pinoLevel = mcpToPinoLevel[level] || "info";
|
|
112346
|
-
const pinoOptions = {
|
|
112347
|
-
level: pinoLevel,
|
|
112348
|
-
base: {
|
|
112349
|
-
env: config2.environment,
|
|
112350
|
-
version: config2.mcpServerVersion,
|
|
112351
|
-
pid: !isServerless2 ? process.pid : undefined
|
|
112352
|
-
},
|
|
112353
|
-
redact: {
|
|
112354
|
-
paths: sanitization.getSensitivePinoFields(),
|
|
112355
|
-
censor: "[REDACTED]"
|
|
112356
|
-
}
|
|
112357
|
-
};
|
|
112358
|
-
if (isServerless2) {
|
|
112359
|
-
return pino(pinoOptions);
|
|
112360
|
-
}
|
|
112361
|
-
const { default: fs2 } = await import("fs");
|
|
112362
|
-
const { default: path2 } = await import("path");
|
|
112363
|
-
const transports = [];
|
|
112364
|
-
const isDevelopment = config2.environment === "development";
|
|
112365
|
-
const isTest = config2.environment === "testing";
|
|
112366
|
-
const noColorEnv = process.env.NO_COLOR === "1" || process.env.FORCE_COLOR === "0";
|
|
112367
|
-
const useColoredOutput = isDevelopment && transportType !== "stdio" && !noColorEnv;
|
|
112368
|
-
if (useColoredOutput && !isServerless2) {
|
|
112369
|
-
try {
|
|
112370
|
-
const { createRequire: createRequire2 } = await import("node:module");
|
|
112371
|
-
const require2 = createRequire2(import.meta.url);
|
|
112372
|
-
const prettyTarget = require2.resolve("pino-pretty");
|
|
112373
|
-
transports.push({
|
|
112374
|
-
target: prettyTarget,
|
|
112375
|
-
options: { colorize: true, translateTime: "yyyy-mm-dd HH:MM:ss" }
|
|
112376
|
-
});
|
|
112377
|
-
} catch (err) {
|
|
112378
|
-
if (process.stderr?.isTTY) {
|
|
112379
|
-
console.warn(`[Logger Init] Pretty transport unavailable (${err instanceof Error ? err.message : String(err)}); falling back to stdout JSON.`);
|
|
112380
|
-
}
|
|
112381
|
-
transports.push({ target: "pino/file", options: { destination: 1 } });
|
|
112382
|
-
}
|
|
112383
|
-
} else if (!isTest) {
|
|
112384
|
-
transports.push({ target: "pino/file", options: { destination: 2 } });
|
|
112385
|
-
}
|
|
112386
|
-
if (config2.logsPath) {
|
|
112387
|
-
try {
|
|
112388
|
-
if (!fs2.existsSync(config2.logsPath)) {
|
|
112389
|
-
fs2.mkdirSync(config2.logsPath, { recursive: true });
|
|
112390
|
-
}
|
|
112391
|
-
transports.push({
|
|
112392
|
-
level: pinoLevel,
|
|
112393
|
-
target: "pino/file",
|
|
112394
|
-
options: {
|
|
112395
|
-
destination: path2.join(config2.logsPath, "combined.log"),
|
|
112396
|
-
mkdir: true
|
|
112397
|
-
}
|
|
112398
|
-
});
|
|
112399
|
-
transports.push({
|
|
112400
|
-
level: "error",
|
|
112401
|
-
target: "pino/file",
|
|
112402
|
-
options: {
|
|
112403
|
-
destination: path2.join(config2.logsPath, "error.log"),
|
|
112404
|
-
mkdir: true
|
|
112405
|
-
}
|
|
112406
|
-
});
|
|
112407
|
-
} catch (err) {
|
|
112408
|
-
if (process.stderr?.isTTY) {
|
|
112409
|
-
console.error(`[Logger Init] Failed to configure file logging: ${err instanceof Error ? err.message : String(err)}`);
|
|
112410
|
-
}
|
|
112411
|
-
}
|
|
112412
|
-
}
|
|
112413
|
-
return pino({ ...pinoOptions, transport: { targets: transports } });
|
|
112414
|
-
}
|
|
112415
|
-
async createInteractionLogger() {
|
|
112416
|
-
if (isServerless2 || !config2.logsPath)
|
|
112417
|
-
return;
|
|
112418
|
-
const { default: path2 } = await import("path");
|
|
112419
|
-
return pino({
|
|
112420
|
-
transport: {
|
|
112421
|
-
target: "pino/file",
|
|
112422
|
-
options: {
|
|
112423
|
-
destination: path2.join(config2.logsPath, "interactions.log"),
|
|
112424
|
-
mkdir: true
|
|
112425
|
-
}
|
|
112426
|
-
}
|
|
112427
|
-
});
|
|
112428
|
-
}
|
|
112429
|
-
async initialize(level = "info", transportType) {
|
|
112430
|
-
if (this.initialized) {
|
|
112431
|
-
this.warning("Logger already initialized.", requestContextService.createRequestContext({
|
|
112432
|
-
operation: "loggerReinit"
|
|
112433
|
-
}));
|
|
112434
|
-
return;
|
|
112435
|
-
}
|
|
112436
|
-
this.currentMcpLevel = level;
|
|
112437
|
-
this.transportType = transportType;
|
|
112438
|
-
this.pinoLogger = await this.createPinoLogger(level, transportType);
|
|
112439
|
-
this.interactionLogger = await this.createInteractionLogger();
|
|
112440
|
-
if (!isServerless2 && !this.cleanupTimer) {
|
|
112441
|
-
this.cleanupTimer = setInterval(() => this.flushSuppressedMessages(), this.rateLimitWindow);
|
|
112442
|
-
this.cleanupTimer.unref?.();
|
|
112443
|
-
}
|
|
112444
|
-
this.initialized = true;
|
|
112445
|
-
this.info(`Logger initialized. MCP level: ${level}.`, requestContextService.createRequestContext({ operation: "loggerInit" }));
|
|
112446
|
-
}
|
|
112447
|
-
setLevel(newLevel) {
|
|
112448
|
-
if (!this.pinoLogger || !this.initialized) {
|
|
112449
|
-
if (process.stderr?.isTTY) {
|
|
112450
|
-
console.error("Cannot set level: Logger not initialized.");
|
|
112451
|
-
}
|
|
112452
|
-
return;
|
|
112453
|
-
}
|
|
112454
|
-
this.currentMcpLevel = newLevel;
|
|
112455
|
-
this.pinoLogger.level = mcpToPinoLevel[newLevel] || "info";
|
|
112456
|
-
this.info(`Log level changed to ${newLevel}.`, requestContextService.createRequestContext({
|
|
112457
|
-
operation: "loggerSetLevel"
|
|
112458
|
-
}));
|
|
112459
|
-
}
|
|
112460
|
-
async close() {
|
|
112461
|
-
if (!this.initialized)
|
|
112462
|
-
return Promise.resolve();
|
|
112463
|
-
this.info("Logger shutting down.", requestContextService.createRequestContext({ operation: "loggerClose" }));
|
|
112464
|
-
if (this.cleanupTimer)
|
|
112465
|
-
clearInterval(this.cleanupTimer);
|
|
112466
|
-
this.flushSuppressedMessages();
|
|
112467
|
-
await Promise.all([
|
|
112468
|
-
new Promise((resolve) => {
|
|
112469
|
-
if (this.pinoLogger) {
|
|
112470
|
-
this.pinoLogger.flush((err) => {
|
|
112471
|
-
if (err && process.stderr?.isTTY && this.transportType !== "stdio") {
|
|
112472
|
-
console.error("Error flushing main logger:", err);
|
|
112473
|
-
}
|
|
112474
|
-
resolve();
|
|
112475
|
-
});
|
|
112476
|
-
} else {
|
|
112477
|
-
resolve();
|
|
112478
|
-
}
|
|
112479
|
-
}),
|
|
112480
|
-
new Promise((resolve) => {
|
|
112481
|
-
if (this.interactionLogger) {
|
|
112482
|
-
this.interactionLogger.flush((err) => {
|
|
112483
|
-
if (err && process.stderr?.isTTY && this.transportType !== "stdio") {
|
|
112484
|
-
console.error("Error flushing interaction logger:", err);
|
|
112485
|
-
}
|
|
112486
|
-
resolve();
|
|
112487
|
-
});
|
|
112488
|
-
} else {
|
|
112489
|
-
resolve();
|
|
112490
|
-
}
|
|
112491
|
-
})
|
|
112492
|
-
]);
|
|
112493
|
-
this.initialized = false;
|
|
112494
|
-
}
|
|
112495
|
-
isInitialized() {
|
|
112496
|
-
return this.initialized;
|
|
112497
|
-
}
|
|
112498
|
-
isRateLimited(message) {
|
|
112499
|
-
const now = Date.now();
|
|
112500
|
-
const entry = this.messageCounts.get(message);
|
|
112501
|
-
if (!entry) {
|
|
112502
|
-
this.messageCounts.set(message, { count: 1, firstSeen: now });
|
|
112503
|
-
return false;
|
|
112504
|
-
}
|
|
112505
|
-
if (now - entry.firstSeen > this.rateLimitWindow) {
|
|
112506
|
-
this.messageCounts.set(message, { count: 1, firstSeen: now });
|
|
112507
|
-
return false;
|
|
112508
|
-
}
|
|
112509
|
-
entry.count++;
|
|
112510
|
-
if (entry.count > this.rateLimitThreshold) {
|
|
112511
|
-
this.suppressedMessages.set(message, (this.suppressedMessages.get(message) || 0) + 1);
|
|
112512
|
-
return true;
|
|
112513
|
-
}
|
|
112514
|
-
return false;
|
|
112515
|
-
}
|
|
112516
|
-
flushSuppressedMessages() {
|
|
112517
|
-
if (this.suppressedMessages.size === 0)
|
|
112518
|
-
return;
|
|
112519
|
-
for (const [message, count] of this.suppressedMessages.entries()) {
|
|
112520
|
-
this.warning(`Log message suppressed ${count} times due to rate limiting.`, requestContextService.createRequestContext({
|
|
112521
|
-
operation: "loggerRateLimitFlush",
|
|
112522
|
-
additionalContext: { originalMessage: message }
|
|
112523
|
-
}));
|
|
112524
|
-
}
|
|
112525
|
-
this.suppressedMessages.clear();
|
|
112526
|
-
this.messageCounts.clear();
|
|
112527
|
-
}
|
|
112528
|
-
log(level, msg, context, error48) {
|
|
112529
|
-
if (!this.pinoLogger || !this.initialized)
|
|
112530
|
-
return;
|
|
112531
|
-
const pinoLevel = mcpToPinoLevel[level] || "info";
|
|
112532
|
-
const currentPinoLevel = mcpToPinoLevel[this.currentMcpLevel] || "info";
|
|
112533
|
-
const levelSeverity = pinoToMcpLevelSeverity[pinoLevel];
|
|
112534
|
-
const currentLevelSeverity = pinoToMcpLevelSeverity[currentPinoLevel];
|
|
112535
|
-
if (typeof levelSeverity === "number" && typeof currentLevelSeverity === "number" && levelSeverity > currentLevelSeverity) {
|
|
112536
|
-
return;
|
|
112537
|
-
}
|
|
112538
|
-
if (this.isRateLimited(msg))
|
|
112539
|
-
return;
|
|
112540
|
-
const logObject = { ...context };
|
|
112541
|
-
if (error48)
|
|
112542
|
-
logObject.err = pino.stdSerializers.err(error48);
|
|
112543
|
-
this.pinoLogger[pinoLevel](logObject, msg);
|
|
112544
|
-
}
|
|
112545
|
-
debug(msg, context) {
|
|
112546
|
-
this.log("debug", msg, context);
|
|
112547
|
-
}
|
|
112548
|
-
info(msg, context) {
|
|
112549
|
-
this.log("info", msg, context);
|
|
112550
|
-
}
|
|
112551
|
-
notice(msg, context) {
|
|
112552
|
-
this.log("notice", msg, context);
|
|
112553
|
-
}
|
|
112554
|
-
warning(msg, context) {
|
|
112555
|
-
this.log("warning", msg, context);
|
|
112556
|
-
}
|
|
112557
|
-
error(msg, errorOrContext, context) {
|
|
112558
|
-
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
112559
|
-
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
112560
|
-
this.log("error", msg, actualContext, errorObj);
|
|
112561
|
-
}
|
|
112562
|
-
crit(msg, errorOrContext, context) {
|
|
112563
|
-
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
112564
|
-
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
112565
|
-
this.log("crit", msg, actualContext, errorObj);
|
|
112566
|
-
}
|
|
112567
|
-
alert(msg, errorOrContext, context) {
|
|
112568
|
-
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
112569
|
-
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
112570
|
-
this.log("alert", msg, actualContext, errorObj);
|
|
112571
|
-
}
|
|
112572
|
-
emerg(msg, errorOrContext, context) {
|
|
112573
|
-
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
112574
|
-
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
112575
|
-
this.log("emerg", msg, actualContext, errorObj);
|
|
112576
|
-
}
|
|
112577
|
-
fatal(msg, errorOrContext, context) {
|
|
112578
|
-
this.emerg(msg, errorOrContext, context);
|
|
112579
|
-
}
|
|
112580
|
-
logInteraction(interactionName, data) {
|
|
112581
|
-
if (!this.interactionLogger) {
|
|
112582
|
-
if (!isServerless2)
|
|
112583
|
-
this.warning("Interaction logger not available.", data.context || {});
|
|
112584
|
-
return;
|
|
112585
|
-
}
|
|
112586
|
-
this.interactionLogger.info({ interactionName, ...data });
|
|
112587
|
-
}
|
|
112588
|
-
};
|
|
112589
|
-
logger = Logger.getInstance();
|
|
112590
|
-
});
|
|
112591
|
-
|
|
112592
|
-
// src/utils/internal/error-handler/mappings.ts
|
|
112593
|
-
var ERROR_TYPE_MAPPINGS, COMMON_ERROR_PATTERNS;
|
|
112594
|
-
var init_mappings = __esm(() => {
|
|
112595
|
-
ERROR_TYPE_MAPPINGS = {
|
|
112596
|
-
SyntaxError: -32007 /* ValidationError */,
|
|
112597
|
-
TypeError: -32007 /* ValidationError */,
|
|
112598
|
-
ReferenceError: -32603 /* InternalError */,
|
|
112599
|
-
RangeError: -32007 /* ValidationError */,
|
|
112600
|
-
URIError: -32007 /* ValidationError */,
|
|
112601
|
-
EvalError: -32603 /* InternalError */,
|
|
112602
|
-
AggregateError: -32603 /* InternalError */
|
|
112603
|
-
};
|
|
112604
|
-
COMMON_ERROR_PATTERNS = [
|
|
112605
|
-
{
|
|
112606
|
-
pattern: /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i,
|
|
112607
|
-
errorCode: -32006 /* Unauthorized */
|
|
112608
|
-
},
|
|
112609
|
-
{
|
|
112610
|
-
pattern: /permission|forbidden|access.*denied|not.*allowed/i,
|
|
112611
|
-
errorCode: -32005 /* Forbidden */
|
|
112612
|
-
},
|
|
112613
|
-
{
|
|
112614
|
-
pattern: /not found|missing|no such|doesn't exist|couldn't find/i,
|
|
112615
|
-
errorCode: -32001 /* NotFound */
|
|
112616
|
-
},
|
|
112617
|
-
{
|
|
112618
|
-
pattern: /invalid|validation|malformed|bad request|wrong format|missing required/i,
|
|
112619
|
-
errorCode: -32007 /* ValidationError */
|
|
112620
|
-
},
|
|
112621
|
-
{
|
|
112622
|
-
pattern: /conflict|already exists|duplicate|unique constraint/i,
|
|
112623
|
-
errorCode: -32002 /* Conflict */
|
|
112624
|
-
},
|
|
112625
|
-
{
|
|
112626
|
-
pattern: /rate limit|too many requests|throttled/i,
|
|
112627
|
-
errorCode: -32003 /* RateLimited */
|
|
112628
|
-
},
|
|
112629
|
-
{
|
|
112630
|
-
pattern: /timeout|timed out|deadline exceeded/i,
|
|
112631
|
-
errorCode: -32004 /* Timeout */
|
|
112632
|
-
},
|
|
112633
|
-
{
|
|
112634
|
-
pattern: /abort(ed)?|cancell?ed/i,
|
|
112635
|
-
errorCode: -32004 /* Timeout */
|
|
112636
|
-
},
|
|
112637
|
-
{
|
|
112638
|
-
pattern: /service unavailable|bad gateway|gateway timeout|upstream error/i,
|
|
112639
|
-
errorCode: -32000 /* ServiceUnavailable */
|
|
112640
|
-
},
|
|
112641
|
-
{
|
|
112642
|
-
pattern: /zod|zoderror|schema validation/i,
|
|
112643
|
-
errorCode: -32007 /* ValidationError */
|
|
112644
|
-
}
|
|
112645
|
-
];
|
|
112646
|
-
});
|
|
112647
|
-
|
|
112648
|
-
// src/utils/internal/error-handler/helpers.ts
|
|
112649
|
-
function createSafeRegex(pattern) {
|
|
112650
|
-
if (pattern instanceof RegExp) {
|
|
112651
|
-
let flags = pattern.flags.replace("g", "");
|
|
112652
|
-
if (!flags.includes("i")) {
|
|
112653
|
-
flags += "i";
|
|
112654
|
-
}
|
|
112655
|
-
return new RegExp(pattern.source, flags);
|
|
112656
|
-
}
|
|
112657
|
-
return new RegExp(pattern, "i");
|
|
112658
|
-
}
|
|
112659
|
-
function getErrorName(error48) {
|
|
112660
|
-
if (error48 instanceof Error) {
|
|
112661
|
-
return error48.name || "Error";
|
|
112662
|
-
}
|
|
112663
|
-
if (error48 === null) {
|
|
112664
|
-
return "NullValueEncountered";
|
|
112665
|
-
}
|
|
112666
|
-
if (error48 === undefined) {
|
|
112667
|
-
return "UndefinedValueEncountered";
|
|
112668
|
-
}
|
|
112669
|
-
if (typeof error48 === "object" && error48 !== null && error48.constructor && typeof error48.constructor.name === "string" && error48.constructor.name !== "Object") {
|
|
112670
|
-
return `${error48.constructor.name}Encountered`;
|
|
112671
|
-
}
|
|
112672
|
-
return `${typeof error48}Encountered`;
|
|
112673
|
-
}
|
|
112674
|
-
function getErrorMessage(error48) {
|
|
112675
|
-
try {
|
|
112676
|
-
if (error48 instanceof Error) {
|
|
112677
|
-
if ("errors" in error48 && Array.isArray(error48.errors)) {
|
|
112678
|
-
const inner = error48.errors.map((e2) => e2 instanceof Error ? e2.message : String(e2)).filter(Boolean).slice(0, 3).join("; ");
|
|
112679
|
-
return inner ? `${error48.message}: ${inner}` : error48.message;
|
|
112680
|
-
}
|
|
112681
|
-
return error48.message;
|
|
112682
|
-
}
|
|
112683
|
-
if (error48 === null) {
|
|
112684
|
-
return "Null value encountered as error";
|
|
112685
|
-
}
|
|
112686
|
-
if (error48 === undefined) {
|
|
112687
|
-
return "Undefined value encountered as error";
|
|
112688
|
-
}
|
|
112689
|
-
if (typeof error48 === "string") {
|
|
112690
|
-
return error48;
|
|
112691
|
-
}
|
|
112692
|
-
if (typeof error48 === "number" || typeof error48 === "boolean") {
|
|
112693
|
-
return String(error48);
|
|
112694
|
-
}
|
|
112695
|
-
if (typeof error48 === "bigint") {
|
|
112696
|
-
return error48.toString();
|
|
112697
|
-
}
|
|
112698
|
-
if (typeof error48 === "function") {
|
|
112699
|
-
return `[function ${error48.name || "anonymous"}]`;
|
|
112700
|
-
}
|
|
112701
|
-
if (typeof error48 === "object") {
|
|
112702
|
-
try {
|
|
112703
|
-
const json2 = JSON.stringify(error48);
|
|
112704
|
-
if (json2 && json2 !== "{}")
|
|
112705
|
-
return json2;
|
|
112706
|
-
} catch {}
|
|
112707
|
-
const ctor = error48.constructor?.name;
|
|
112708
|
-
return `Non-Error object encountered (constructor: ${ctor || "Object"})`;
|
|
112709
|
-
}
|
|
112710
|
-
if (typeof error48 === "symbol") {
|
|
112711
|
-
return error48.toString();
|
|
112712
|
-
}
|
|
112713
|
-
return "[unrepresentable error]";
|
|
112714
|
-
} catch (conversionError) {
|
|
112715
|
-
return `Error converting error to string: ${conversionError instanceof Error ? conversionError.message : "Unknown conversion error"}`;
|
|
112716
|
-
}
|
|
112717
|
-
}
|
|
112718
|
-
|
|
112719
|
-
// src/utils/internal/error-handler/errorHandler.ts
|
|
112720
|
-
class ErrorHandler {
|
|
112721
|
-
static determineErrorCode(error48) {
|
|
112722
|
-
if (error48 instanceof McpError) {
|
|
112723
|
-
return error48.code;
|
|
112724
|
-
}
|
|
112725
|
-
const errorName = getErrorName(error48);
|
|
112726
|
-
const errorMessage = getErrorMessage(error48);
|
|
112727
|
-
const mappedFromType = ERROR_TYPE_MAPPINGS[errorName];
|
|
112728
|
-
if (mappedFromType) {
|
|
112729
|
-
return mappedFromType;
|
|
112730
|
-
}
|
|
112731
|
-
for (const mapping of COMMON_ERROR_PATTERNS) {
|
|
112732
|
-
const regex = createSafeRegex(mapping.pattern);
|
|
112733
|
-
if (regex.test(errorMessage) || regex.test(errorName)) {
|
|
112734
|
-
return mapping.errorCode;
|
|
112735
|
-
}
|
|
112736
|
-
}
|
|
112737
|
-
if (typeof error48 === "object" && error48 !== null && "name" in error48 && error48.name === "AbortError") {
|
|
112738
|
-
return -32004 /* Timeout */;
|
|
112739
|
-
}
|
|
112740
|
-
return -32603 /* InternalError */;
|
|
112741
|
-
}
|
|
112742
|
-
static handleError(error48, options) {
|
|
112743
|
-
const activeSpan = import_api3.trace.getActiveSpan();
|
|
112744
|
-
if (activeSpan) {
|
|
112745
|
-
if (error48 instanceof Error) {
|
|
112746
|
-
activeSpan.recordException(error48);
|
|
112747
|
-
}
|
|
112748
|
-
activeSpan.setStatus({
|
|
112749
|
-
code: import_api3.SpanStatusCode.ERROR,
|
|
112750
|
-
message: error48 instanceof Error ? error48.message : String(error48)
|
|
112751
|
-
});
|
|
112752
|
-
}
|
|
112753
|
-
const {
|
|
112754
|
-
context = {},
|
|
112755
|
-
operation,
|
|
112756
|
-
input,
|
|
112757
|
-
rethrow = false,
|
|
112758
|
-
errorCode: explicitErrorCode,
|
|
112759
|
-
includeStack = true,
|
|
112760
|
-
critical = false,
|
|
112761
|
-
errorMapper
|
|
112762
|
-
} = options;
|
|
112763
|
-
const sanitizedInput = input !== undefined ? sanitizeInputForLogging(input) : undefined;
|
|
112764
|
-
const originalErrorName = getErrorName(error48);
|
|
112765
|
-
const originalErrorMessage = getErrorMessage(error48);
|
|
112766
|
-
const originalStack = error48 instanceof Error ? error48.stack : undefined;
|
|
112767
|
-
let finalError;
|
|
112768
|
-
let loggedErrorCode;
|
|
112769
|
-
const errorDataSeed = error48 instanceof McpError && typeof error48.data === "object" && error48.data !== null ? { ...error48.data } : {};
|
|
112770
|
-
const consolidatedData = {
|
|
112771
|
-
...errorDataSeed,
|
|
112772
|
-
...context,
|
|
112773
|
-
originalErrorName,
|
|
112774
|
-
originalMessage: originalErrorMessage
|
|
112775
|
-
};
|
|
112776
|
-
if (originalStack && !(error48 instanceof McpError && error48.data?.originalStack)) {
|
|
112777
|
-
consolidatedData.originalStack = originalStack;
|
|
112778
|
-
}
|
|
112779
|
-
const cause = error48 instanceof Error ? error48 : undefined;
|
|
112780
|
-
const rootCause = (() => {
|
|
112781
|
-
let current = cause;
|
|
112782
|
-
let depth = 0;
|
|
112783
|
-
while (current && current instanceof Error && current.cause && depth < 5) {
|
|
112784
|
-
current = current.cause;
|
|
112785
|
-
depth += 1;
|
|
112786
|
-
}
|
|
112787
|
-
return current instanceof Error ? { name: current.name, message: current.message } : undefined;
|
|
112788
|
-
})();
|
|
112789
|
-
if (rootCause) {
|
|
112790
|
-
consolidatedData["rootCause"] = rootCause;
|
|
112791
|
-
}
|
|
112792
|
-
if (error48 instanceof McpError) {
|
|
112793
|
-
loggedErrorCode = error48.code;
|
|
112794
|
-
finalError = errorMapper ? errorMapper(error48) : new McpError(error48.code, error48.message, consolidatedData, {
|
|
112795
|
-
cause
|
|
112796
|
-
});
|
|
112797
|
-
} else {
|
|
112798
|
-
loggedErrorCode = explicitErrorCode || ErrorHandler.determineErrorCode(error48);
|
|
112799
|
-
const message = `Error in ${operation}: ${originalErrorMessage}`;
|
|
112800
|
-
finalError = errorMapper ? errorMapper(error48) : new McpError(loggedErrorCode, message, consolidatedData, {
|
|
112801
|
-
cause
|
|
112802
|
-
});
|
|
112803
|
-
}
|
|
112804
|
-
if (finalError !== error48 && error48 instanceof Error && finalError instanceof Error && !finalError.stack && error48.stack) {
|
|
112805
|
-
finalError.stack = error48.stack;
|
|
112806
|
-
}
|
|
112807
|
-
const logRequestId = typeof context.requestId === "string" && context.requestId ? context.requestId : generateUUID();
|
|
112808
|
-
const logTimestamp = typeof context.timestamp === "string" && context.timestamp ? context.timestamp : new Date().toISOString();
|
|
112809
|
-
const stack = finalError instanceof Error ? finalError.stack : originalStack;
|
|
112810
|
-
const logContext = {
|
|
112811
|
-
requestId: logRequestId,
|
|
112812
|
-
timestamp: logTimestamp,
|
|
112813
|
-
operation,
|
|
112814
|
-
input: sanitizedInput,
|
|
112815
|
-
critical,
|
|
112816
|
-
errorCode: loggedErrorCode,
|
|
112817
|
-
originalErrorType: originalErrorName,
|
|
112818
|
-
finalErrorType: getErrorName(finalError),
|
|
112819
|
-
...Object.fromEntries(Object.entries(context).filter(([key]) => key !== "requestId" && key !== "timestamp")),
|
|
112820
|
-
errorData: finalError instanceof McpError && finalError.data ? finalError.data : consolidatedData,
|
|
112821
|
-
...includeStack && stack ? { stack } : {}
|
|
112822
|
-
};
|
|
112823
|
-
logger.error(`Error in ${operation}: ${finalError.message || originalErrorMessage}`, logContext);
|
|
112824
|
-
if (rethrow) {
|
|
112825
|
-
throw finalError;
|
|
112826
|
-
}
|
|
112827
|
-
return finalError;
|
|
112828
|
-
}
|
|
112829
|
-
static mapError(error48, mappings, defaultFactory) {
|
|
112830
|
-
const errorMessage = getErrorMessage(error48);
|
|
112831
|
-
const errorName = getErrorName(error48);
|
|
112832
|
-
for (const mapping of mappings) {
|
|
112833
|
-
const regex = createSafeRegex(mapping.pattern);
|
|
112834
|
-
if (regex.test(errorMessage) || regex.test(errorName)) {
|
|
112835
|
-
return mapping.factory(error48, mapping.additionalContext);
|
|
112836
|
-
}
|
|
112837
|
-
}
|
|
112838
|
-
if (defaultFactory) {
|
|
112839
|
-
return defaultFactory(error48);
|
|
112840
|
-
}
|
|
112841
|
-
return error48 instanceof Error ? error48 : new Error(String(error48));
|
|
112842
|
-
}
|
|
112843
|
-
static formatError(error48) {
|
|
112844
|
-
if (error48 instanceof McpError) {
|
|
112845
|
-
return {
|
|
112846
|
-
code: error48.code,
|
|
112847
|
-
message: error48.message,
|
|
112848
|
-
data: typeof error48.data === "object" && error48.data !== null ? error48.data : {}
|
|
112849
|
-
};
|
|
112850
|
-
}
|
|
112851
|
-
if (error48 instanceof Error) {
|
|
112852
|
-
return {
|
|
112853
|
-
code: ErrorHandler.determineErrorCode(error48),
|
|
112854
|
-
message: error48.message,
|
|
112855
|
-
data: { errorType: error48.name || "Error" }
|
|
112856
|
-
};
|
|
112857
|
-
}
|
|
112858
|
-
return {
|
|
112859
|
-
code: -32099 /* UnknownError */,
|
|
112860
|
-
message: getErrorMessage(error48),
|
|
112861
|
-
data: { errorType: getErrorName(error48) }
|
|
112862
|
-
};
|
|
112863
|
-
}
|
|
112864
|
-
static async tryCatch(fn, options) {
|
|
112865
|
-
try {
|
|
112866
|
-
return await Promise.resolve(fn());
|
|
112867
|
-
} catch (caughtError) {
|
|
112868
|
-
throw ErrorHandler.handleError(caughtError, {
|
|
112869
|
-
...options,
|
|
112870
|
-
rethrow: true
|
|
112871
|
-
});
|
|
112872
|
-
}
|
|
112873
|
-
}
|
|
112874
|
-
}
|
|
112875
|
-
var import_api3;
|
|
112876
|
-
var init_errorHandler = __esm(() => {
|
|
112877
|
-
init_errors3();
|
|
112878
|
-
init_utils();
|
|
112879
|
-
init_logger();
|
|
112880
|
-
init_mappings();
|
|
112881
|
-
import_api3 = __toESM(require_src(), 1);
|
|
112882
|
-
});
|
|
112883
|
-
|
|
112884
|
-
// src/utils/internal/error-handler/index.ts
|
|
112885
|
-
var init_error_handler = __esm(() => {
|
|
112886
|
-
init_errorHandler();
|
|
112887
|
-
});
|
|
112888
|
-
|
|
112889
|
-
// src/utils/internal/runtime.ts
|
|
112890
|
-
function detectRuntime() {
|
|
112891
|
-
if (runtimeCaps.isBun) {
|
|
112892
|
-
return "bun";
|
|
112893
|
-
}
|
|
112894
|
-
if (runtimeCaps.isNode) {
|
|
112895
|
-
return "node";
|
|
112896
|
-
}
|
|
112897
|
-
if (runtimeCaps.isWorkerLike) {
|
|
112898
|
-
return "worker";
|
|
112899
|
-
}
|
|
112900
|
-
if (runtimeCaps.isBrowserLike) {
|
|
112901
|
-
return "browser";
|
|
112902
|
-
}
|
|
112903
|
-
return "unknown";
|
|
112904
|
-
}
|
|
112905
|
-
function getRuntimeDescription() {
|
|
112906
|
-
const runtime = detectRuntime();
|
|
112907
|
-
switch (runtime) {
|
|
112908
|
-
case "bun":
|
|
112909
|
-
return `Bun ${process.versions?.bun || "unknown"}`;
|
|
112910
|
-
case "node":
|
|
112911
|
-
return `Node.js ${process.versions?.node || "unknown"}`;
|
|
112912
|
-
case "worker":
|
|
112913
|
-
return "Cloudflare Workers / Web Worker";
|
|
112914
|
-
case "browser":
|
|
112915
|
-
return "Browser";
|
|
112916
|
-
default:
|
|
112917
|
-
return "Unknown runtime";
|
|
112918
|
-
}
|
|
112919
|
-
}
|
|
112920
|
-
var safeHas = (key) => {
|
|
112921
|
-
try {
|
|
112922
|
-
return typeof globalThis[key] !== "undefined";
|
|
112923
|
-
} catch {
|
|
112924
|
-
return false;
|
|
112925
|
-
}
|
|
112926
|
-
}, isBun, isNode, hasProcess, hasBuffer, hasTextEncoder, hasPerformanceNow, isWorkerLike, isBrowserLike, runtimeCaps;
|
|
112927
|
-
var init_runtime = __esm(() => {
|
|
112928
|
-
isBun = typeof globalThis.Bun !== "undefined" || typeof process.versions?.bun === "string";
|
|
112929
|
-
isNode = !isBun && typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
112930
|
-
hasProcess = typeof process !== "undefined";
|
|
112931
|
-
hasBuffer = typeof Buffer !== "undefined";
|
|
112932
|
-
hasTextEncoder = safeHas("TextEncoder");
|
|
112933
|
-
hasPerformanceNow = typeof globalThis.performance?.now === "function";
|
|
112934
|
-
isWorkerLike = !isNode && !isBun && typeof globalThis.WorkerGlobalScope !== "undefined";
|
|
112935
|
-
isBrowserLike = !isNode && !isBun && !isWorkerLike && safeHas("window");
|
|
112936
|
-
runtimeCaps = {
|
|
112937
|
-
isNode,
|
|
112938
|
-
isBun,
|
|
112939
|
-
isWorkerLike,
|
|
112940
|
-
isBrowserLike,
|
|
112941
|
-
hasProcess,
|
|
112942
|
-
hasBuffer,
|
|
112943
|
-
hasTextEncoder,
|
|
112944
|
-
hasPerformanceNow
|
|
112945
|
-
};
|
|
112946
|
-
});
|
|
112947
|
-
|
|
112948
|
-
// src/utils/internal/health.ts
|
|
112949
|
-
function getHealthSnapshot() {
|
|
112950
|
-
return {
|
|
112951
|
-
app: {
|
|
112952
|
-
name: config2.mcpServerName,
|
|
112953
|
-
version: config2.mcpServerVersion,
|
|
112954
|
-
environment: config2.environment
|
|
112955
|
-
},
|
|
112956
|
-
runtime: {
|
|
112957
|
-
isNode: runtimeCaps.isNode,
|
|
112958
|
-
isWorkerLike: runtimeCaps.isWorkerLike,
|
|
112959
|
-
isBrowserLike: runtimeCaps.isBrowserLike
|
|
112960
|
-
},
|
|
112961
|
-
telemetry: {
|
|
112962
|
-
enabled: Boolean(config2.openTelemetry.enabled),
|
|
112963
|
-
diagLevel: config2.openTelemetry.logLevel
|
|
112964
|
-
},
|
|
112965
|
-
logging: {
|
|
112966
|
-
initialized: logger.isInitialized()
|
|
112967
|
-
}
|
|
112968
|
-
};
|
|
112969
|
-
}
|
|
112970
|
-
var init_health = __esm(() => {
|
|
112971
|
-
init_config();
|
|
112972
|
-
init_logger();
|
|
112973
|
-
init_runtime();
|
|
112974
|
-
});
|
|
112975
|
-
|
|
112976
|
-
// src/utils/telemetry/semconv.ts
|
|
112977
|
-
var ATTR_CODE_FUNCTION = "code.function", ATTR_CODE_NAMESPACE = "code.namespace", ATTR_MCP_TOOL_INPUT_BYTES = "mcp.tool.input_bytes", ATTR_MCP_TOOL_OUTPUT_BYTES = "mcp.tool.output_bytes", ATTR_MCP_TOOL_DURATION_MS = "mcp.tool.duration_ms", ATTR_MCP_TOOL_SUCCESS = "mcp.tool.success", ATTR_MCP_TOOL_ERROR_CODE = "mcp.tool.error_code", ATTR_MCP_TOOL_MEMORY_RSS_BEFORE = "mcp.tool.memory_rss_bytes.before", ATTR_MCP_TOOL_MEMORY_RSS_AFTER = "mcp.tool.memory_rss_bytes.after", ATTR_MCP_TOOL_MEMORY_RSS_DELTA = "mcp.tool.memory_rss_bytes.delta", ATTR_MCP_TOOL_MEMORY_HEAP_USED_BEFORE = "mcp.tool.memory_heap_used_bytes.before", ATTR_MCP_TOOL_MEMORY_HEAP_USED_AFTER = "mcp.tool.memory_heap_used_bytes.after", ATTR_MCP_TOOL_MEMORY_HEAP_USED_DELTA = "mcp.tool.memory_heap_used_bytes.delta";
|
|
112978
|
-
|
|
112979
|
-
// src/utils/internal/performance.ts
|
|
112980
|
-
async function loadPerfHooks() {
|
|
112981
|
-
return import("perf_hooks");
|
|
112982
|
-
}
|
|
112983
|
-
async function initializePerformance_Hrt() {
|
|
112984
|
-
const globalWithPerf = globalThis;
|
|
112985
|
-
if (typeof globalWithPerf.performance?.now === "function") {
|
|
112986
|
-
const perf = globalWithPerf.performance;
|
|
112987
|
-
performanceNow = () => perf?.now() ?? Date.now();
|
|
112988
|
-
} else {
|
|
112989
|
-
try {
|
|
112990
|
-
const { performance: nodePerformance } = await loadPerfHooks();
|
|
112991
|
-
performanceNow = () => nodePerformance.now();
|
|
112992
|
-
} catch (_e) {
|
|
112993
|
-
performanceNow = () => Date.now();
|
|
112994
|
-
logger.warning("Could not import perf_hooks, falling back to Date.now() for performance timing.");
|
|
112995
|
-
}
|
|
112996
|
-
}
|
|
112997
|
-
}
|
|
112998
|
-
async function measureToolExecution(toolLogicFn, context, inputPayload) {
|
|
112999
|
-
const tracer = import_api4.trace.getTracer(config2.openTelemetry.serviceName, config2.openTelemetry.serviceVersion);
|
|
113000
|
-
const { toolName } = context;
|
|
113001
|
-
return tracer.startActiveSpan(`tool_execution:${toolName}`, async (span) => {
|
|
113002
|
-
const memBefore = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { rss: 0, heapUsed: 0 };
|
|
113003
|
-
const t0 = nowMs();
|
|
113004
|
-
span.setAttributes({
|
|
113005
|
-
[ATTR_CODE_FUNCTION]: toolName,
|
|
113006
|
-
[ATTR_CODE_NAMESPACE]: "mcp-tools",
|
|
113007
|
-
[ATTR_MCP_TOOL_INPUT_BYTES]: toBytes(inputPayload),
|
|
113008
|
-
[ATTR_MCP_TOOL_MEMORY_RSS_BEFORE]: memBefore.rss,
|
|
113009
|
-
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_BEFORE]: memBefore.heapUsed
|
|
113010
|
-
});
|
|
113011
|
-
let ok = false;
|
|
113012
|
-
let errorCode;
|
|
113013
|
-
let output;
|
|
113014
|
-
try {
|
|
113015
|
-
const result = await toolLogicFn();
|
|
113016
|
-
ok = true;
|
|
113017
|
-
output = result;
|
|
113018
|
-
span.setStatus({ code: import_api4.SpanStatusCode.OK });
|
|
113019
|
-
span.setAttribute(ATTR_MCP_TOOL_OUTPUT_BYTES, toBytes(output));
|
|
113020
|
-
return result;
|
|
113021
|
-
} catch (err) {
|
|
113022
|
-
if (err instanceof McpError)
|
|
113023
|
-
errorCode = String(err.code);
|
|
113024
|
-
else if (err instanceof Error)
|
|
113025
|
-
errorCode = "UNHANDLED_ERROR";
|
|
113026
|
-
else
|
|
113027
|
-
errorCode = "UNKNOWN_ERROR";
|
|
113028
|
-
if (err instanceof Error)
|
|
113029
|
-
span.recordException(err);
|
|
113030
|
-
span.setStatus({
|
|
113031
|
-
code: import_api4.SpanStatusCode.ERROR,
|
|
113032
|
-
message: err instanceof Error ? err.message : String(err)
|
|
113033
|
-
});
|
|
113034
|
-
throw err;
|
|
113035
|
-
} finally {
|
|
113036
|
-
const t1 = nowMs();
|
|
113037
|
-
const durationMs = Number((t1 - t0).toFixed(2));
|
|
113038
|
-
const memAfter = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { rss: 0, heapUsed: 0 };
|
|
113039
|
-
const rssDelta = memAfter.rss - memBefore.rss;
|
|
113040
|
-
const heapUsedDelta = memAfter.heapUsed - memBefore.heapUsed;
|
|
113041
|
-
span.setAttributes({
|
|
113042
|
-
[ATTR_MCP_TOOL_DURATION_MS]: durationMs,
|
|
113043
|
-
[ATTR_MCP_TOOL_SUCCESS]: ok,
|
|
113044
|
-
[ATTR_MCP_TOOL_MEMORY_RSS_AFTER]: memAfter.rss,
|
|
113045
|
-
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_AFTER]: memAfter.heapUsed,
|
|
113046
|
-
[ATTR_MCP_TOOL_MEMORY_RSS_DELTA]: rssDelta,
|
|
113047
|
-
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_DELTA]: heapUsedDelta
|
|
113048
|
-
});
|
|
113049
|
-
if (errorCode)
|
|
113050
|
-
span.setAttribute(ATTR_MCP_TOOL_ERROR_CODE, errorCode);
|
|
113051
|
-
span.end();
|
|
113052
|
-
logger.info("Tool execution finished.", {
|
|
113053
|
-
...context,
|
|
113054
|
-
metrics: {
|
|
113055
|
-
durationMs,
|
|
113056
|
-
isSuccess: ok,
|
|
113057
|
-
errorCode,
|
|
113058
|
-
inputBytes: toBytes(inputPayload),
|
|
113059
|
-
outputBytes: toBytes(output),
|
|
113060
|
-
memory: {
|
|
113061
|
-
rss: {
|
|
113062
|
-
before: memBefore.rss,
|
|
113063
|
-
after: memAfter.rss,
|
|
113064
|
-
delta: rssDelta
|
|
113065
|
-
},
|
|
113066
|
-
heapUsed: {
|
|
113067
|
-
before: memBefore.heapUsed,
|
|
113068
|
-
after: memAfter.heapUsed,
|
|
113069
|
-
delta: heapUsedDelta
|
|
113070
|
-
}
|
|
113071
|
-
}
|
|
113072
|
-
}
|
|
113073
|
-
});
|
|
113074
|
-
}
|
|
113075
|
-
});
|
|
113076
|
-
}
|
|
113077
|
-
var import_api4, performanceNow = () => Date.now(), nowMs = () => performanceNow(), toBytes = (payload) => {
|
|
113078
|
-
if (payload == null)
|
|
113079
|
-
return 0;
|
|
113080
|
-
try {
|
|
113081
|
-
const json2 = JSON.stringify(payload);
|
|
113082
|
-
if (typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function") {
|
|
113083
|
-
const bytes = Buffer.byteLength(json2, "utf8");
|
|
113084
|
-
return bytes;
|
|
113085
|
-
}
|
|
113086
|
-
if (typeof TextEncoder !== "undefined") {
|
|
113087
|
-
return new TextEncoder().encode(json2).length;
|
|
113088
|
-
}
|
|
113089
|
-
return json2.length;
|
|
113090
|
-
} catch {
|
|
113091
|
-
return 0;
|
|
113092
|
-
}
|
|
113093
|
-
};
|
|
113094
|
-
var init_performance = __esm(() => {
|
|
113095
|
-
init_config();
|
|
113096
|
-
init_errors3();
|
|
113097
|
-
init_logger();
|
|
113098
|
-
import_api4 = __toESM(require_src(), 1);
|
|
113099
|
-
});
|
|
113100
|
-
|
|
113101
|
-
// src/utils/internal/startupBanner.ts
|
|
113102
|
-
function logStartupBanner(message, transportType) {
|
|
113103
|
-
if (process.stdout.isTTY) {
|
|
113104
|
-
if (transportType === "stdio") {
|
|
113105
|
-
console.error(message);
|
|
113106
|
-
} else {
|
|
113107
|
-
console.log(message);
|
|
113108
|
-
}
|
|
113109
|
-
}
|
|
113110
|
-
}
|
|
113111
|
-
|
|
113112
|
-
// src/utils/internal/index.ts
|
|
113113
|
-
var init_internal = __esm(() => {
|
|
113114
|
-
init_error_handler();
|
|
113115
|
-
init_health();
|
|
113116
|
-
init_logger();
|
|
113117
|
-
init_performance();
|
|
113118
|
-
init_requestContext();
|
|
113119
|
-
init_runtime();
|
|
113120
|
-
});
|
|
113121
|
-
|
|
113122
|
-
// src/utils/metrics/tokenCounter.ts
|
|
113123
|
-
function getModelHeuristics(model) {
|
|
113124
|
-
const key = (model ?? DEFAULT_MODEL).toLowerCase();
|
|
113125
|
-
const found = HEURISTICS[key];
|
|
113126
|
-
return found ?? HEURISTICS.default;
|
|
113127
|
-
}
|
|
113128
|
-
function nonEmptyString(s2) {
|
|
113129
|
-
return typeof s2 === "string" && s2.length > 0;
|
|
113130
|
-
}
|
|
113131
|
-
function approxTokenCount(text, charsPerToken) {
|
|
113132
|
-
if (!text)
|
|
113133
|
-
return 0;
|
|
113134
|
-
const normalized = text.replace(/\s+/g, " ").trim();
|
|
113135
|
-
if (!normalized)
|
|
113136
|
-
return 0;
|
|
113137
|
-
return Math.ceil(normalized.length / Math.max(1, charsPerToken));
|
|
113138
|
-
}
|
|
113139
|
-
async function countTokens(text, context, model) {
|
|
113140
|
-
return ErrorHandler.tryCatch(() => {
|
|
113141
|
-
const h2 = getModelHeuristics(model);
|
|
113142
|
-
return approxTokenCount(text ?? "", h2.charsPerToken);
|
|
113143
|
-
}, {
|
|
113144
|
-
operation: "countTokens",
|
|
113145
|
-
...context && { context },
|
|
113146
|
-
input: {
|
|
113147
|
-
textSample: nonEmptyString(text) ? text.length > 53 ? `${text.slice(0, 50)}...` : text : ""
|
|
113148
|
-
},
|
|
113149
|
-
errorCode: -32603 /* InternalError */
|
|
113150
|
-
});
|
|
113151
|
-
}
|
|
113152
|
-
async function countChatTokens(messages, context, model) {
|
|
113153
|
-
return ErrorHandler.tryCatch(() => {
|
|
113154
|
-
const h2 = getModelHeuristics(model);
|
|
113155
|
-
let tokens = 0;
|
|
113156
|
-
for (const message of messages) {
|
|
113157
|
-
tokens += h2.tokensPerMessage;
|
|
113158
|
-
tokens += 1;
|
|
113159
|
-
if (typeof message.content === "string") {
|
|
113160
|
-
tokens += approxTokenCount(message.content, h2.charsPerToken);
|
|
113161
|
-
} else if (Array.isArray(message.content)) {
|
|
113162
|
-
for (const part of message.content) {
|
|
113163
|
-
if (part && part.type === "text" && nonEmptyString(part.text)) {
|
|
113164
|
-
tokens += approxTokenCount(part.text, h2.charsPerToken);
|
|
113165
|
-
} else if (part) {
|
|
113166
|
-
logger.warning(`Non-text content part found (type: ${String(part.type)}), token count contribution ignored.`, context);
|
|
113167
|
-
}
|
|
113168
|
-
}
|
|
113169
|
-
}
|
|
113170
|
-
if (message.name) {
|
|
113171
|
-
tokens += h2.tokensPerName;
|
|
113172
|
-
tokens += approxTokenCount(message.name, h2.charsPerToken);
|
|
113173
|
-
}
|
|
113174
|
-
if (message.role === "assistant" && Array.isArray(message.tool_calls)) {
|
|
113175
|
-
for (const toolCall of message.tool_calls) {
|
|
113176
|
-
if (toolCall?.type === "function") {
|
|
113177
|
-
if (toolCall.function?.name) {
|
|
113178
|
-
tokens += approxTokenCount(toolCall.function.name, h2.charsPerToken);
|
|
113179
|
-
}
|
|
113180
|
-
if (toolCall.function?.arguments) {
|
|
113181
|
-
tokens += approxTokenCount(toolCall.function.arguments, h2.charsPerToken);
|
|
113182
|
-
}
|
|
113183
|
-
}
|
|
113184
|
-
}
|
|
113185
|
-
}
|
|
113186
|
-
if (message.role === "tool" && message.tool_call_id) {
|
|
113187
|
-
tokens += approxTokenCount(message.tool_call_id, h2.charsPerToken);
|
|
113188
|
-
}
|
|
113189
|
-
}
|
|
113190
|
-
tokens += h2.replyPrimer;
|
|
113191
|
-
return tokens;
|
|
113192
|
-
}, {
|
|
113193
|
-
operation: "countChatTokens",
|
|
113194
|
-
...context && { context },
|
|
113195
|
-
input: { messageCount: messages.length },
|
|
113196
|
-
errorCode: -32603 /* InternalError */
|
|
113197
|
-
});
|
|
113198
|
-
}
|
|
113199
|
-
var DEFAULT_MODEL = "gpt-4o", HEURISTICS;
|
|
113200
|
-
var init_tokenCounter = __esm(() => {
|
|
113201
|
-
init_utils();
|
|
113202
|
-
HEURISTICS = {
|
|
113203
|
-
"gpt-4o": {
|
|
113204
|
-
charsPerToken: 4,
|
|
113205
|
-
tokensPerMessage: 3,
|
|
113206
|
-
tokensPerName: 1,
|
|
113207
|
-
replyPrimer: 3
|
|
113208
|
-
},
|
|
113209
|
-
"gpt-4o-mini": {
|
|
113210
|
-
charsPerToken: 4,
|
|
113211
|
-
tokensPerMessage: 3,
|
|
113212
|
-
tokensPerName: 1,
|
|
113213
|
-
replyPrimer: 3
|
|
113214
|
-
},
|
|
113215
|
-
default: {
|
|
113216
|
-
charsPerToken: 4,
|
|
113217
|
-
tokensPerMessage: 3,
|
|
113218
|
-
tokensPerName: 1,
|
|
113219
|
-
replyPrimer: 3
|
|
113220
|
-
}
|
|
113221
|
-
};
|
|
113222
|
-
});
|
|
113223
|
-
|
|
113224
|
-
// src/utils/metrics/registry.ts
|
|
113225
|
-
function getMeter() {
|
|
113226
|
-
return import_api5.metrics.getMeter(config2.openTelemetry.serviceName, config2.openTelemetry.serviceVersion);
|
|
113227
|
-
}
|
|
113228
|
-
function isEnabled() {
|
|
113229
|
-
return Boolean(config2.openTelemetry.enabled);
|
|
113230
|
-
}
|
|
113231
|
-
function getCounter(name, description, unit) {
|
|
113232
|
-
if (!isEnabled()) {
|
|
113233
|
-
return {
|
|
113234
|
-
add: () => {
|
|
113235
|
-
return;
|
|
113236
|
-
},
|
|
113237
|
-
bind: () => ({ add: () => {
|
|
113238
|
-
return;
|
|
113239
|
-
} }),
|
|
113240
|
-
unbind: () => {
|
|
113241
|
-
return;
|
|
113242
|
-
}
|
|
113243
|
-
};
|
|
113244
|
-
}
|
|
113245
|
-
const key = `${name}|${description ?? ""}|${unit ?? ""}`;
|
|
113246
|
-
const existing = counters.get(key);
|
|
113247
|
-
if (existing)
|
|
113248
|
-
return existing;
|
|
113249
|
-
const opts = {};
|
|
113250
|
-
if (description !== undefined)
|
|
113251
|
-
opts.description = description;
|
|
113252
|
-
if (unit !== undefined)
|
|
113253
|
-
opts.unit = unit;
|
|
113254
|
-
const counter = Object.keys(opts).length ? getMeter().createCounter(name, opts) : getMeter().createCounter(name);
|
|
113255
|
-
counters.set(key, counter);
|
|
113256
|
-
return counter;
|
|
113257
|
-
}
|
|
113258
|
-
function getHistogram(name, description, unit) {
|
|
113259
|
-
if (!isEnabled()) {
|
|
113260
|
-
return {
|
|
113261
|
-
record: () => {
|
|
113262
|
-
return;
|
|
113263
|
-
},
|
|
113264
|
-
bind: () => ({ record: () => {
|
|
113265
|
-
return;
|
|
113266
|
-
} }),
|
|
113267
|
-
unbind: () => {
|
|
113268
|
-
return;
|
|
113269
|
-
}
|
|
113270
|
-
};
|
|
113271
|
-
}
|
|
113272
|
-
const key = `${name}|${description ?? ""}|${unit ?? ""}`;
|
|
113273
|
-
const existing = histograms.get(key);
|
|
113274
|
-
if (existing)
|
|
113275
|
-
return existing;
|
|
113276
|
-
const opts = {};
|
|
113277
|
-
if (description !== undefined)
|
|
113278
|
-
opts.description = description;
|
|
113279
|
-
if (unit !== undefined)
|
|
113280
|
-
opts.unit = unit;
|
|
113281
|
-
const histogram = Object.keys(opts).length ? getMeter().createHistogram(name, opts) : getMeter().createHistogram(name);
|
|
113282
|
-
histograms.set(key, histogram);
|
|
113283
|
-
return histogram;
|
|
113284
|
-
}
|
|
113285
|
-
function add(name, value, attributes, description, unit) {
|
|
113286
|
-
const c = getCounter(name, description, unit);
|
|
113287
|
-
c.add(value, attributes);
|
|
113288
|
-
}
|
|
113289
|
-
function record2(name, value, attributes, description, unit) {
|
|
113290
|
-
const h2 = getHistogram(name, description, unit);
|
|
113291
|
-
h2.record(value, attributes);
|
|
113292
|
-
}
|
|
113293
|
-
var import_api5, counters, histograms, metricsRegistry;
|
|
113294
|
-
var init_registry = __esm(() => {
|
|
113295
|
-
init_config();
|
|
113296
|
-
import_api5 = __toESM(require_src(), 1);
|
|
113297
|
-
counters = new Map;
|
|
113298
|
-
histograms = new Map;
|
|
113299
|
-
metricsRegistry = {
|
|
113300
|
-
getCounter,
|
|
113301
|
-
getHistogram,
|
|
113302
|
-
add,
|
|
113303
|
-
record: record2,
|
|
113304
|
-
enabled: isEnabled
|
|
113305
|
-
};
|
|
113306
|
-
});
|
|
113307
|
-
|
|
113308
|
-
// src/utils/metrics/index.ts
|
|
113309
|
-
var init_metrics = __esm(() => {
|
|
113310
|
-
init_tokenCounter();
|
|
113311
|
-
init_registry();
|
|
113312
|
-
});
|
|
113313
|
-
|
|
113314
|
-
// src/utils/security/idGenerator.ts
|
|
113315
|
-
import { randomUUID as cryptoRandomUUID, randomBytes } from "crypto";
|
|
113316
|
-
|
|
113317
|
-
class IdGenerator {
|
|
113318
|
-
static DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
113319
|
-
static DEFAULT_SEPARATOR = "_";
|
|
113320
|
-
static DEFAULT_LENGTH = 6;
|
|
113321
|
-
entityPrefixes = {};
|
|
113322
|
-
prefixToEntityType = {};
|
|
113323
|
-
constructor(entityPrefixes = {}) {
|
|
113324
|
-
this.setEntityPrefixes(entityPrefixes);
|
|
113325
|
-
}
|
|
113326
|
-
setEntityPrefixes(entityPrefixes) {
|
|
113327
|
-
this.entityPrefixes = { ...entityPrefixes };
|
|
113328
|
-
this.prefixToEntityType = Object.entries(this.entityPrefixes).reduce((acc, [type, prefix]) => {
|
|
113329
|
-
acc[prefix.toLowerCase()] = type;
|
|
113330
|
-
return acc;
|
|
113331
|
-
}, {});
|
|
113332
|
-
}
|
|
113333
|
-
getEntityPrefixes() {
|
|
113334
|
-
return { ...this.entityPrefixes };
|
|
113335
|
-
}
|
|
113336
|
-
generateRandomString(length = IdGenerator.DEFAULT_LENGTH, charset = IdGenerator.DEFAULT_CHARSET) {
|
|
113337
|
-
let result = "";
|
|
113338
|
-
const maxValidByteValue = Math.floor(256 / charset.length) * charset.length;
|
|
113339
|
-
while (result.length < length) {
|
|
113340
|
-
const byteBuffer = randomBytes(1);
|
|
113341
|
-
const byte = byteBuffer[0];
|
|
113342
|
-
if (byte !== undefined && byte < maxValidByteValue) {
|
|
113343
|
-
const charIndex = byte % charset.length;
|
|
113344
|
-
const char = charset[charIndex];
|
|
113345
|
-
if (char) {
|
|
113346
|
-
result += char;
|
|
113347
|
-
}
|
|
113348
|
-
}
|
|
113349
|
-
}
|
|
113350
|
-
return result;
|
|
113351
|
-
}
|
|
113352
|
-
generate(prefix, options = {}) {
|
|
113353
|
-
const {
|
|
113354
|
-
length = IdGenerator.DEFAULT_LENGTH,
|
|
113355
|
-
separator = IdGenerator.DEFAULT_SEPARATOR,
|
|
113356
|
-
charset = IdGenerator.DEFAULT_CHARSET
|
|
113357
|
-
} = options;
|
|
113358
|
-
const randomPart = this.generateRandomString(length, charset);
|
|
113359
|
-
const generatedId = prefix ? `${prefix}${separator}${randomPart}` : randomPart;
|
|
113360
|
-
return generatedId;
|
|
113361
|
-
}
|
|
113362
|
-
generateForEntity(entityType, options = {}) {
|
|
113363
|
-
const prefix = this.entityPrefixes[entityType];
|
|
113364
|
-
if (!prefix) {
|
|
113365
|
-
throw new McpError(-32007 /* ValidationError */, `Unknown entity type: ${entityType}. No prefix registered.`);
|
|
113366
|
-
}
|
|
113367
|
-
return this.generate(prefix, options);
|
|
113368
|
-
}
|
|
113369
|
-
isValid(id, entityType, options = {}) {
|
|
113370
|
-
const prefix = this.entityPrefixes[entityType];
|
|
113371
|
-
const {
|
|
113372
|
-
length = IdGenerator.DEFAULT_LENGTH,
|
|
113373
|
-
separator = IdGenerator.DEFAULT_SEPARATOR,
|
|
113374
|
-
charset = IdGenerator.DEFAULT_CHARSET
|
|
113375
|
-
} = options;
|
|
113376
|
-
if (!prefix) {
|
|
113377
|
-
return false;
|
|
113378
|
-
}
|
|
113379
|
-
const escapedCharsetForClass = charset.replace(/[[\]\\^-]/g, "\\$&");
|
|
113380
|
-
const charsetRegexPart = `[${escapedCharsetForClass}]`;
|
|
113381
|
-
const pattern = new RegExp(`^${this.escapeRegex(prefix)}${this.escapeRegex(separator)}${charsetRegexPart}{${length}}$`);
|
|
113382
|
-
return pattern.test(id);
|
|
113383
|
-
}
|
|
113384
|
-
escapeRegex(str) {
|
|
113385
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
113386
|
-
}
|
|
113387
|
-
stripPrefix(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
113388
|
-
const parts = id.split(separator);
|
|
113389
|
-
return parts.length > 1 ? parts.slice(1).join(separator) : id;
|
|
113390
|
-
}
|
|
113391
|
-
getEntityType(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
113392
|
-
const parts = id.split(separator);
|
|
113393
|
-
if (parts.length < 2 || !parts[0]) {
|
|
113394
|
-
throw new McpError(-32007 /* ValidationError */, `Invalid ID format: ${id}. Expected format like: PREFIX${separator}RANDOMLPART`);
|
|
113395
|
-
}
|
|
113396
|
-
const prefix = parts[0];
|
|
113397
|
-
const entityType = this.prefixToEntityType[prefix.toLowerCase()];
|
|
113398
|
-
if (!entityType) {
|
|
113399
|
-
throw new McpError(-32007 /* ValidationError */, `Unknown entity type for prefix: ${prefix}`);
|
|
113400
|
-
}
|
|
113401
|
-
return entityType;
|
|
113402
|
-
}
|
|
113403
|
-
normalize(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
113404
|
-
const entityType = this.getEntityType(id, separator);
|
|
113405
|
-
const registeredPrefix = this.entityPrefixes[entityType];
|
|
113406
|
-
const idParts = id.split(separator);
|
|
113407
|
-
const randomPart = idParts.slice(1).join(separator);
|
|
113408
|
-
return `${registeredPrefix}${separator}${randomPart.toUpperCase()}`;
|
|
113409
|
-
}
|
|
113410
|
-
}
|
|
113411
|
-
var idGenerator, generateUUID = () => {
|
|
113412
|
-
return cryptoRandomUUID();
|
|
113413
|
-
}, generateRequestContextId = () => {
|
|
113414
|
-
const generateSecureRandomString = (length, charset2) => {
|
|
113415
|
-
let result = "";
|
|
113416
|
-
const maxValidByteValue = Math.floor(256 / charset2.length) * charset2.length;
|
|
113417
|
-
while (result.length < length) {
|
|
113418
|
-
const byteBuffer = randomBytes(1);
|
|
113419
|
-
const byte = byteBuffer[0];
|
|
113420
|
-
if (byte !== undefined && byte < maxValidByteValue) {
|
|
113421
|
-
const charIndex = byte % charset2.length;
|
|
113422
|
-
const char = charset2[charIndex];
|
|
113423
|
-
if (char) {
|
|
113424
|
-
result += char;
|
|
113425
|
-
}
|
|
113426
|
-
}
|
|
113427
|
-
}
|
|
113428
|
-
return result;
|
|
113429
|
-
};
|
|
113430
|
-
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
113431
|
-
const part1 = generateSecureRandomString(5, charset);
|
|
113432
|
-
const part2 = generateSecureRandomString(5, charset);
|
|
113433
|
-
return `${part1}-${part2}`;
|
|
113434
|
-
};
|
|
113435
|
-
var init_idGenerator = __esm(() => {
|
|
113436
|
-
init_errors3();
|
|
113437
|
-
idGenerator = new IdGenerator;
|
|
113438
|
-
});
|
|
113439
|
-
|
|
113440
111980
|
// node_modules/tsyringe/node_modules/tslib/tslib.js
|
|
113441
111981
|
var require_tslib = __commonJS((exports, module) => {
|
|
113442
111982
|
/*! *****************************************************************************
|
|
@@ -114582,7 +113122,7 @@ var require_registry2 = __commonJS((exports) => {
|
|
|
114582
113122
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
114583
113123
|
var tslib_1 = require_tslib();
|
|
114584
113124
|
var dependency_container_1 = require_dependency_container();
|
|
114585
|
-
function
|
|
113125
|
+
function registry2(registrations = []) {
|
|
114586
113126
|
return function(target) {
|
|
114587
113127
|
registrations.forEach((_a2) => {
|
|
114588
113128
|
var { token, options } = _a2, provider = tslib_1.__rest(_a2, ["token", "options"]);
|
|
@@ -114591,7 +113131,7 @@ var require_registry2 = __commonJS((exports) => {
|
|
|
114591
113131
|
return target;
|
|
114592
113132
|
};
|
|
114593
113133
|
}
|
|
114594
|
-
exports.default =
|
|
113134
|
+
exports.default = registry2;
|
|
114595
113135
|
});
|
|
114596
113136
|
|
|
114597
113137
|
// node_modules/tsyringe/dist/cjs/decorators/singleton.js
|
|
@@ -114835,195 +113375,6 @@ var init_tokens = __esm(() => {
|
|
|
114835
113375
|
GitProviderFactory = Symbol("GitProviderFactory");
|
|
114836
113376
|
});
|
|
114837
113377
|
|
|
114838
|
-
// src/utils/security/rateLimiter.ts
|
|
114839
|
-
var import_api6, import_tsyringe, RateLimiter;
|
|
114840
|
-
var init_rateLimiter = __esm(() => {
|
|
114841
|
-
init_tokens();
|
|
114842
|
-
init_errors3();
|
|
114843
|
-
init_utils();
|
|
114844
|
-
import_api6 = __toESM(require_src(), 1);
|
|
114845
|
-
import_tsyringe = __toESM(require_cjs2(), 1);
|
|
114846
|
-
RateLimiter = class RateLimiter {
|
|
114847
|
-
config;
|
|
114848
|
-
logger;
|
|
114849
|
-
limits;
|
|
114850
|
-
cleanupTimer = null;
|
|
114851
|
-
effectiveConfig;
|
|
114852
|
-
constructor(config3, logger3) {
|
|
114853
|
-
this.config = config3;
|
|
114854
|
-
this.logger = logger3;
|
|
114855
|
-
const defaultConfig = {
|
|
114856
|
-
windowMs: 15 * 60 * 1000,
|
|
114857
|
-
maxRequests: 100,
|
|
114858
|
-
errorMessage: "Rate limit exceeded. Please try again in {waitTime} seconds.",
|
|
114859
|
-
skipInDevelopment: false,
|
|
114860
|
-
cleanupInterval: 5 * 60 * 1000
|
|
114861
|
-
};
|
|
114862
|
-
this.effectiveConfig = { ...defaultConfig };
|
|
114863
|
-
this.limits = new Map;
|
|
114864
|
-
this.startCleanupTimer();
|
|
114865
|
-
}
|
|
114866
|
-
startCleanupTimer() {
|
|
114867
|
-
if (this.cleanupTimer) {
|
|
114868
|
-
clearInterval(this.cleanupTimer);
|
|
114869
|
-
}
|
|
114870
|
-
const interval = this.effectiveConfig.cleanupInterval;
|
|
114871
|
-
if (interval && interval > 0) {
|
|
114872
|
-
this.cleanupTimer = setInterval(() => {
|
|
114873
|
-
this.cleanupExpiredEntries();
|
|
114874
|
-
}, interval);
|
|
114875
|
-
if (this.cleanupTimer.unref) {
|
|
114876
|
-
this.cleanupTimer.unref();
|
|
114877
|
-
}
|
|
114878
|
-
}
|
|
114879
|
-
}
|
|
114880
|
-
cleanupExpiredEntries() {
|
|
114881
|
-
const now = Date.now();
|
|
114882
|
-
let expiredCount = 0;
|
|
114883
|
-
for (const [key, entry] of this.limits.entries()) {
|
|
114884
|
-
if (now >= entry.resetTime) {
|
|
114885
|
-
this.limits.delete(key);
|
|
114886
|
-
expiredCount++;
|
|
114887
|
-
}
|
|
114888
|
-
}
|
|
114889
|
-
if (expiredCount > 0) {
|
|
114890
|
-
const logContext = requestContextService.createRequestContext({
|
|
114891
|
-
operation: "RateLimiter.cleanupExpiredEntries",
|
|
114892
|
-
additionalContext: {
|
|
114893
|
-
cleanedCount: expiredCount,
|
|
114894
|
-
totalRemainingAfterClean: this.limits.size
|
|
114895
|
-
}
|
|
114896
|
-
});
|
|
114897
|
-
this.logger.debug(`Cleaned up ${expiredCount} expired rate limit entries`, logContext);
|
|
114898
|
-
}
|
|
114899
|
-
}
|
|
114900
|
-
configure(config3) {
|
|
114901
|
-
Object.assign(this.effectiveConfig, config3);
|
|
114902
|
-
if (config3.cleanupInterval !== undefined) {
|
|
114903
|
-
this.startCleanupTimer();
|
|
114904
|
-
}
|
|
114905
|
-
}
|
|
114906
|
-
getConfig() {
|
|
114907
|
-
return { ...this.effectiveConfig };
|
|
114908
|
-
}
|
|
114909
|
-
reset() {
|
|
114910
|
-
this.limits.clear();
|
|
114911
|
-
const logContext = requestContextService.createRequestContext({
|
|
114912
|
-
operation: "RateLimiter.reset"
|
|
114913
|
-
});
|
|
114914
|
-
this.logger.debug("Rate limiter reset, all limits cleared", logContext);
|
|
114915
|
-
}
|
|
114916
|
-
check(key, context) {
|
|
114917
|
-
const activeSpan = import_api6.trace.getActiveSpan();
|
|
114918
|
-
activeSpan?.setAttribute("mcp.rate_limit.checked", true);
|
|
114919
|
-
if (this.effectiveConfig.skipInDevelopment && this.config.environment === "development") {
|
|
114920
|
-
activeSpan?.setAttribute("mcp.rate_limit.skipped", "development");
|
|
114921
|
-
return;
|
|
114922
|
-
}
|
|
114923
|
-
const limitKey = this.effectiveConfig.keyGenerator ? this.effectiveConfig.keyGenerator(key, context) : key;
|
|
114924
|
-
activeSpan?.setAttribute("mcp.rate_limit.key", limitKey);
|
|
114925
|
-
const now = Date.now();
|
|
114926
|
-
let entry = this.limits.get(limitKey);
|
|
114927
|
-
if (!entry || now >= entry.resetTime) {
|
|
114928
|
-
entry = {
|
|
114929
|
-
count: 1,
|
|
114930
|
-
resetTime: now + this.effectiveConfig.windowMs
|
|
114931
|
-
};
|
|
114932
|
-
this.limits.set(limitKey, entry);
|
|
114933
|
-
} else {
|
|
114934
|
-
entry.count++;
|
|
114935
|
-
}
|
|
114936
|
-
const remaining = Math.max(0, this.effectiveConfig.maxRequests - entry.count);
|
|
114937
|
-
activeSpan?.setAttributes({
|
|
114938
|
-
"mcp.rate_limit.limit": this.effectiveConfig.maxRequests,
|
|
114939
|
-
"mcp.rate_limit.count": entry.count,
|
|
114940
|
-
"mcp.rate_limit.remaining": remaining
|
|
114941
|
-
});
|
|
114942
|
-
if (entry.count > this.effectiveConfig.maxRequests) {
|
|
114943
|
-
const waitTime = Math.ceil((entry.resetTime - now) / 1000);
|
|
114944
|
-
const errorMessage = (this.effectiveConfig.errorMessage || "Rate limit exceeded. Please try again in {waitTime} seconds.").replace("{waitTime}", waitTime.toString());
|
|
114945
|
-
activeSpan?.addEvent("rate_limit_exceeded", {
|
|
114946
|
-
"mcp.rate_limit.wait_time_seconds": waitTime
|
|
114947
|
-
});
|
|
114948
|
-
throw new McpError(-32003 /* RateLimited */, errorMessage, {
|
|
114949
|
-
waitTimeSeconds: waitTime,
|
|
114950
|
-
key: limitKey,
|
|
114951
|
-
limit: this.effectiveConfig.maxRequests,
|
|
114952
|
-
windowMs: this.effectiveConfig.windowMs
|
|
114953
|
-
});
|
|
114954
|
-
}
|
|
114955
|
-
}
|
|
114956
|
-
getStatus(key) {
|
|
114957
|
-
const entry = this.limits.get(key);
|
|
114958
|
-
if (!entry)
|
|
114959
|
-
return null;
|
|
114960
|
-
return {
|
|
114961
|
-
current: entry.count,
|
|
114962
|
-
limit: this.effectiveConfig.maxRequests,
|
|
114963
|
-
remaining: Math.max(0, this.effectiveConfig.maxRequests - entry.count),
|
|
114964
|
-
resetTime: entry.resetTime
|
|
114965
|
-
};
|
|
114966
|
-
}
|
|
114967
|
-
dispose() {
|
|
114968
|
-
if (this.cleanupTimer) {
|
|
114969
|
-
clearInterval(this.cleanupTimer);
|
|
114970
|
-
this.cleanupTimer = null;
|
|
114971
|
-
}
|
|
114972
|
-
this.limits.clear();
|
|
114973
|
-
}
|
|
114974
|
-
};
|
|
114975
|
-
RateLimiter = __legacyDecorateClassTS([
|
|
114976
|
-
import_tsyringe.injectable(),
|
|
114977
|
-
__legacyDecorateParamTS(0, import_tsyringe.inject(AppConfig)),
|
|
114978
|
-
__legacyDecorateParamTS(1, import_tsyringe.inject(Logger2)),
|
|
114979
|
-
__legacyMetadataTS("design:paramtypes", [
|
|
114980
|
-
Object,
|
|
114981
|
-
Object
|
|
114982
|
-
])
|
|
114983
|
-
], RateLimiter);
|
|
114984
|
-
});
|
|
114985
|
-
|
|
114986
|
-
// src/utils/security/index.ts
|
|
114987
|
-
var init_security = __esm(() => {
|
|
114988
|
-
init_idGenerator();
|
|
114989
|
-
init_rateLimiter();
|
|
114990
|
-
init_sanitization();
|
|
114991
|
-
});
|
|
114992
|
-
|
|
114993
|
-
// src/utils/index.ts
|
|
114994
|
-
var exports_utils = {};
|
|
114995
|
-
__export(exports_utils, {
|
|
114996
|
-
sanitizeInputForLogging: () => sanitizeInputForLogging,
|
|
114997
|
-
sanitization: () => sanitization,
|
|
114998
|
-
runtimeCaps: () => runtimeCaps,
|
|
114999
|
-
requestContextService: () => requestContextService,
|
|
115000
|
-
nowMs: () => nowMs,
|
|
115001
|
-
metricsRegistry: () => metricsRegistry,
|
|
115002
|
-
measureToolExecution: () => measureToolExecution,
|
|
115003
|
-
logger: () => logger,
|
|
115004
|
-
logStartupBanner: () => logStartupBanner,
|
|
115005
|
-
loadPerfHooks: () => loadPerfHooks,
|
|
115006
|
-
initializePerformance_Hrt: () => initializePerformance_Hrt,
|
|
115007
|
-
idGenerator: () => idGenerator,
|
|
115008
|
-
getRuntimeDescription: () => getRuntimeDescription,
|
|
115009
|
-
getHealthSnapshot: () => getHealthSnapshot,
|
|
115010
|
-
generateUUID: () => generateUUID,
|
|
115011
|
-
generateRequestContextId: () => generateRequestContextId,
|
|
115012
|
-
detectRuntime: () => detectRuntime,
|
|
115013
|
-
countTokens: () => countTokens,
|
|
115014
|
-
countChatTokens: () => countChatTokens,
|
|
115015
|
-
Sanitization: () => Sanitization,
|
|
115016
|
-
RateLimiter: () => RateLimiter,
|
|
115017
|
-
Logger: () => Logger,
|
|
115018
|
-
IdGenerator: () => IdGenerator,
|
|
115019
|
-
ErrorHandler: () => ErrorHandler
|
|
115020
|
-
});
|
|
115021
|
-
var init_utils = __esm(() => {
|
|
115022
|
-
init_internal();
|
|
115023
|
-
init_metrics();
|
|
115024
|
-
init_security();
|
|
115025
|
-
});
|
|
115026
|
-
|
|
115027
113378
|
// node_modules/tslib/tslib.js
|
|
115028
113379
|
var require_tslib2 = __commonJS((exports, module) => {
|
|
115029
113380
|
var __extends;
|
|
@@ -116159,22 +114510,22 @@ var require_transformers = __commonJS((exports) => {
|
|
|
116159
114510
|
PostgresTypes2["tsrange"] = "tsrange";
|
|
116160
114511
|
PostgresTypes2["tstzrange"] = "tstzrange";
|
|
116161
114512
|
})(PostgresTypes || (exports.PostgresTypes = PostgresTypes = {}));
|
|
116162
|
-
var convertChangeData = (columns,
|
|
114513
|
+
var convertChangeData = (columns, record2, options = {}) => {
|
|
116163
114514
|
var _a2;
|
|
116164
114515
|
const skipTypes = (_a2 = options.skipTypes) !== null && _a2 !== undefined ? _a2 : [];
|
|
116165
|
-
if (!
|
|
114516
|
+
if (!record2) {
|
|
116166
114517
|
return {};
|
|
116167
114518
|
}
|
|
116168
|
-
return Object.keys(
|
|
116169
|
-
acc[rec_key] = (0, exports.convertColumn)(rec_key, columns,
|
|
114519
|
+
return Object.keys(record2).reduce((acc, rec_key) => {
|
|
114520
|
+
acc[rec_key] = (0, exports.convertColumn)(rec_key, columns, record2, skipTypes);
|
|
116170
114521
|
return acc;
|
|
116171
114522
|
}, {});
|
|
116172
114523
|
};
|
|
116173
114524
|
exports.convertChangeData = convertChangeData;
|
|
116174
|
-
var convertColumn = (columnName, columns,
|
|
114525
|
+
var convertColumn = (columnName, columns, record2, skipTypes) => {
|
|
116175
114526
|
const column = columns.find((x2) => x2.name === columnName);
|
|
116176
114527
|
const colType = column === null || column === undefined ? undefined : column.type;
|
|
116177
|
-
const value =
|
|
114528
|
+
const value = record2[columnName];
|
|
116178
114529
|
if (colType && !skipTypes.includes(colType)) {
|
|
116179
114530
|
return (0, exports.convertCell)(colType, value);
|
|
116180
114531
|
}
|
|
@@ -127939,13 +126290,13 @@ var require_core = __commonJS((exports) => {
|
|
|
127939
126290
|
return metaOpts;
|
|
127940
126291
|
}
|
|
127941
126292
|
var noLogs = { log() {}, warn() {}, error() {} };
|
|
127942
|
-
function getLogger(
|
|
127943
|
-
if (
|
|
126293
|
+
function getLogger(logger2) {
|
|
126294
|
+
if (logger2 === false)
|
|
127944
126295
|
return noLogs;
|
|
127945
|
-
if (
|
|
126296
|
+
if (logger2 === undefined)
|
|
127946
126297
|
return console;
|
|
127947
|
-
if (
|
|
127948
|
-
return
|
|
126298
|
+
if (logger2.log && logger2.warn && logger2.error)
|
|
126299
|
+
return logger2;
|
|
127949
126300
|
throw new Error("logger must implement log, warn and error methods");
|
|
127950
126301
|
}
|
|
127951
126302
|
var KEYWORD_NAME = /^[a-z_$][a-z0-9_$:-]*$/i;
|
|
@@ -130290,10 +128641,1377 @@ async function shutdownOpenTelemetry() {
|
|
|
130290
128641
|
}
|
|
130291
128642
|
}
|
|
130292
128643
|
|
|
130293
|
-
// src/
|
|
130294
|
-
|
|
130295
|
-
|
|
130296
|
-
|
|
128644
|
+
// src/utils/internal/error-handler/errorHandler.ts
|
|
128645
|
+
init_errors3();
|
|
128646
|
+
var import_api3 = __toESM(require_src(), 1);
|
|
128647
|
+
|
|
128648
|
+
// src/utils/internal/logger.ts
|
|
128649
|
+
init_config();
|
|
128650
|
+
import pino from "pino";
|
|
128651
|
+
|
|
128652
|
+
// src/utils/internal/requestContext.ts
|
|
128653
|
+
var import_api2 = __toESM(require_src(), 1);
|
|
128654
|
+
|
|
128655
|
+
// src/mcp-server/transports/auth/lib/authContext.ts
|
|
128656
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
128657
|
+
var authContext = new AsyncLocalStorage;
|
|
128658
|
+
|
|
128659
|
+
// src/utils/internal/requestContext.ts
|
|
128660
|
+
var requestContextServiceInstance = {
|
|
128661
|
+
config: {},
|
|
128662
|
+
configure(config3) {
|
|
128663
|
+
this.config = {
|
|
128664
|
+
...this.config,
|
|
128665
|
+
...config3
|
|
128666
|
+
};
|
|
128667
|
+
const logContext = this.createRequestContext({
|
|
128668
|
+
operation: "RequestContextService.configure",
|
|
128669
|
+
additionalContext: { newConfigState: { ...this.config } }
|
|
128670
|
+
});
|
|
128671
|
+
logger.debug("RequestContextService configuration updated", logContext);
|
|
128672
|
+
return { ...this.config };
|
|
128673
|
+
},
|
|
128674
|
+
getConfig() {
|
|
128675
|
+
return { ...this.config };
|
|
128676
|
+
},
|
|
128677
|
+
createRequestContext(params = {}) {
|
|
128678
|
+
const { parentContext, additionalContext, operation, ...rest } = params;
|
|
128679
|
+
const inheritedContext = parentContext && typeof parentContext === "object" ? { ...parentContext } : {};
|
|
128680
|
+
let inheritedTenantId;
|
|
128681
|
+
if (inheritedContext && typeof inheritedContext === "object" && "tenantId" in inheritedContext && typeof inheritedContext.tenantId === "string") {
|
|
128682
|
+
inheritedTenantId = inheritedContext.tenantId;
|
|
128683
|
+
}
|
|
128684
|
+
const authStore = authContext.getStore();
|
|
128685
|
+
const tenantIdFromAuth = authStore?.authInfo?.tenantId;
|
|
128686
|
+
const inheritedRequestId = inheritedContext.requestId;
|
|
128687
|
+
const requestId = typeof inheritedRequestId === "string" && inheritedRequestId ? inheritedRequestId : generateRequestContextId();
|
|
128688
|
+
const timestamp = new Date().toISOString();
|
|
128689
|
+
const restTenantId = typeof rest.tenantId === "string" ? rest.tenantId : undefined;
|
|
128690
|
+
const additionalTenantId = additionalContext && typeof additionalContext === "object" && typeof additionalContext.tenantId === "string" ? additionalContext.tenantId : undefined;
|
|
128691
|
+
const resolvedTenantId = additionalTenantId ?? restTenantId ?? inheritedTenantId ?? tenantIdFromAuth;
|
|
128692
|
+
const context = {
|
|
128693
|
+
...inheritedContext,
|
|
128694
|
+
...rest,
|
|
128695
|
+
requestId,
|
|
128696
|
+
timestamp,
|
|
128697
|
+
...resolvedTenantId ? { tenantId: resolvedTenantId } : {},
|
|
128698
|
+
...additionalContext && typeof additionalContext === "object" ? additionalContext : {},
|
|
128699
|
+
...operation && typeof operation === "string" ? { operation } : {}
|
|
128700
|
+
};
|
|
128701
|
+
const activeSpan = import_api2.trace.getActiveSpan();
|
|
128702
|
+
if (activeSpan && typeof activeSpan.spanContext === "function") {
|
|
128703
|
+
const spanContext = activeSpan.spanContext();
|
|
128704
|
+
if (spanContext) {
|
|
128705
|
+
context.traceId = spanContext.traceId;
|
|
128706
|
+
context.spanId = spanContext.spanId;
|
|
128707
|
+
}
|
|
128708
|
+
}
|
|
128709
|
+
return context;
|
|
128710
|
+
}
|
|
128711
|
+
};
|
|
128712
|
+
var requestContextService = requestContextServiceInstance;
|
|
128713
|
+
|
|
128714
|
+
// src/utils/security/sanitization.ts
|
|
128715
|
+
init_errors3();
|
|
128716
|
+
var import_validator = __toESM(require_validator(), 1);
|
|
128717
|
+
var isServerless = typeof process === "undefined" || process.env.IS_SERVERLESS === "true";
|
|
128718
|
+
var pathModule;
|
|
128719
|
+
if (!isServerless) {
|
|
128720
|
+
import("path").then((mod2) => {
|
|
128721
|
+
pathModule = mod2.default;
|
|
128722
|
+
}).catch(() => {});
|
|
128723
|
+
}
|
|
128724
|
+
|
|
128725
|
+
class Sanitization {
|
|
128726
|
+
static instance;
|
|
128727
|
+
sensitiveFields = [
|
|
128728
|
+
"password",
|
|
128729
|
+
"token",
|
|
128730
|
+
"secret",
|
|
128731
|
+
"apiKey",
|
|
128732
|
+
"credential",
|
|
128733
|
+
"jwt",
|
|
128734
|
+
"ssn",
|
|
128735
|
+
"cvv",
|
|
128736
|
+
"authorization",
|
|
128737
|
+
"cookie",
|
|
128738
|
+
"clientsecret",
|
|
128739
|
+
"client_secret",
|
|
128740
|
+
"private_key",
|
|
128741
|
+
"privatekey"
|
|
128742
|
+
];
|
|
128743
|
+
constructor() {}
|
|
128744
|
+
static getInstance() {
|
|
128745
|
+
if (!Sanitization.instance) {
|
|
128746
|
+
Sanitization.instance = new Sanitization;
|
|
128747
|
+
}
|
|
128748
|
+
return Sanitization.instance;
|
|
128749
|
+
}
|
|
128750
|
+
setSensitiveFields(fields) {
|
|
128751
|
+
this.sensitiveFields = [
|
|
128752
|
+
...new Set([
|
|
128753
|
+
...this.sensitiveFields,
|
|
128754
|
+
...fields.map((f3) => f3.toLowerCase())
|
|
128755
|
+
])
|
|
128756
|
+
];
|
|
128757
|
+
const logContext = requestContextService.createRequestContext({
|
|
128758
|
+
operation: "Sanitization.setSensitiveFields",
|
|
128759
|
+
additionalContext: {
|
|
128760
|
+
newSensitiveFieldCount: this.sensitiveFields.length
|
|
128761
|
+
}
|
|
128762
|
+
});
|
|
128763
|
+
logger.debug("Updated sensitive fields list for log sanitization", logContext);
|
|
128764
|
+
}
|
|
128765
|
+
getSensitiveFields() {
|
|
128766
|
+
return [...this.sensitiveFields];
|
|
128767
|
+
}
|
|
128768
|
+
getSensitivePinoFields() {
|
|
128769
|
+
return this.sensitiveFields.map((field) => field.replace(/[-_]/g, ""));
|
|
128770
|
+
}
|
|
128771
|
+
sanitizeUrl(input, allowedProtocols = ["http", "https"]) {
|
|
128772
|
+
try {
|
|
128773
|
+
const trimmedInput = input.trim();
|
|
128774
|
+
if (!import_validator.default.isURL(trimmedInput, {
|
|
128775
|
+
protocols: allowedProtocols,
|
|
128776
|
+
require_protocol: true,
|
|
128777
|
+
require_host: true
|
|
128778
|
+
})) {
|
|
128779
|
+
throw new Error("Invalid URL format or protocol not in allowed list.");
|
|
128780
|
+
}
|
|
128781
|
+
const lowercasedInput = trimmedInput.toLowerCase();
|
|
128782
|
+
if (lowercasedInput.startsWith("javascript:") || lowercasedInput.startsWith("data:") || lowercasedInput.startsWith("vbscript:")) {
|
|
128783
|
+
throw new Error("Disallowed pseudo-protocol (javascript:, data:, or vbscript:) in URL.");
|
|
128784
|
+
}
|
|
128785
|
+
return trimmedInput;
|
|
128786
|
+
} catch (error48) {
|
|
128787
|
+
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid or unsafe URL provided.", { input });
|
|
128788
|
+
}
|
|
128789
|
+
}
|
|
128790
|
+
sanitizePath(input, options = {}) {
|
|
128791
|
+
if (isServerless || !pathModule) {
|
|
128792
|
+
throw new McpError(-32603 /* InternalError */, "File-based path sanitization is not supported in this environment.");
|
|
128793
|
+
}
|
|
128794
|
+
const path2 = pathModule;
|
|
128795
|
+
const originalInput = input;
|
|
128796
|
+
const resolvedRootDir = options.rootDir ? path2.resolve(options.rootDir) : undefined;
|
|
128797
|
+
const effectiveOptions = {
|
|
128798
|
+
toPosix: options.toPosix ?? false,
|
|
128799
|
+
allowAbsolute: options.allowAbsolute ?? false,
|
|
128800
|
+
...resolvedRootDir && { rootDir: resolvedRootDir }
|
|
128801
|
+
};
|
|
128802
|
+
let wasAbsoluteInitially = false;
|
|
128803
|
+
try {
|
|
128804
|
+
if (!input || typeof input !== "string")
|
|
128805
|
+
throw new Error("Invalid path input: must be a non-empty string.");
|
|
128806
|
+
if (input.includes("\x00"))
|
|
128807
|
+
throw new Error("Path contains null byte, which is disallowed.");
|
|
128808
|
+
let normalized = path2.normalize(input);
|
|
128809
|
+
wasAbsoluteInitially = path2.isAbsolute(normalized);
|
|
128810
|
+
if (effectiveOptions.toPosix) {
|
|
128811
|
+
normalized = normalized.replace(/\\/g, "/");
|
|
128812
|
+
}
|
|
128813
|
+
let finalSanitizedPath;
|
|
128814
|
+
if (resolvedRootDir) {
|
|
128815
|
+
let fullPath;
|
|
128816
|
+
if (path2.isAbsolute(normalized)) {
|
|
128817
|
+
fullPath = path2.normalize(normalized);
|
|
128818
|
+
} else {
|
|
128819
|
+
fullPath = path2.resolve(resolvedRootDir, normalized);
|
|
128820
|
+
}
|
|
128821
|
+
const normalizedRoot = path2.normalize(resolvedRootDir);
|
|
128822
|
+
const normalizedFull = path2.normalize(fullPath);
|
|
128823
|
+
if (!normalizedFull.startsWith(normalizedRoot + path2.sep) && normalizedFull !== normalizedRoot) {
|
|
128824
|
+
throw new Error("Path traversal detected: attempts to escape the defined root directory.");
|
|
128825
|
+
}
|
|
128826
|
+
finalSanitizedPath = path2.relative(normalizedRoot, normalizedFull);
|
|
128827
|
+
finalSanitizedPath = finalSanitizedPath === "" ? "." : finalSanitizedPath;
|
|
128828
|
+
if (path2.isAbsolute(finalSanitizedPath) && !effectiveOptions.allowAbsolute) {
|
|
128829
|
+
throw new Error("Path resolved to absolute outside root when absolute paths are disallowed.");
|
|
128830
|
+
}
|
|
128831
|
+
} else {
|
|
128832
|
+
if (path2.isAbsolute(normalized)) {
|
|
128833
|
+
if (!effectiveOptions.allowAbsolute) {
|
|
128834
|
+
throw new Error("Absolute paths are disallowed by current options.");
|
|
128835
|
+
} else {
|
|
128836
|
+
finalSanitizedPath = normalized;
|
|
128837
|
+
}
|
|
128838
|
+
} else {
|
|
128839
|
+
const resolvedAgainstCwd = path2.resolve(normalized);
|
|
128840
|
+
const currentWorkingDir = path2.resolve(".");
|
|
128841
|
+
if (!resolvedAgainstCwd.startsWith(currentWorkingDir + path2.sep) && resolvedAgainstCwd !== currentWorkingDir) {
|
|
128842
|
+
throw new Error("Relative path traversal detected (escapes current working directory context).");
|
|
128843
|
+
}
|
|
128844
|
+
finalSanitizedPath = normalized;
|
|
128845
|
+
}
|
|
128846
|
+
}
|
|
128847
|
+
return {
|
|
128848
|
+
sanitizedPath: finalSanitizedPath,
|
|
128849
|
+
originalInput,
|
|
128850
|
+
wasAbsolute: wasAbsoluteInitially,
|
|
128851
|
+
convertedToRelative: wasAbsoluteInitially && !path2.isAbsolute(finalSanitizedPath) && !effectiveOptions.allowAbsolute,
|
|
128852
|
+
optionsUsed: effectiveOptions
|
|
128853
|
+
};
|
|
128854
|
+
} catch (error48) {
|
|
128855
|
+
logger.warning("Path sanitization error", requestContextService.createRequestContext({
|
|
128856
|
+
operation: "Sanitization.sanitizePath.error",
|
|
128857
|
+
additionalContext: {
|
|
128858
|
+
originalPathInput: originalInput,
|
|
128859
|
+
pathOptionsUsed: effectiveOptions,
|
|
128860
|
+
errorMessage: error48 instanceof Error ? error48.message : String(error48)
|
|
128861
|
+
}
|
|
128862
|
+
}));
|
|
128863
|
+
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid or unsafe path provided.", { input: originalInput });
|
|
128864
|
+
}
|
|
128865
|
+
}
|
|
128866
|
+
sanitizeJson(input, maxSize) {
|
|
128867
|
+
try {
|
|
128868
|
+
if (typeof input !== "string")
|
|
128869
|
+
throw new Error("Invalid input: expected a JSON string.");
|
|
128870
|
+
const computeBytes = (s2) => {
|
|
128871
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function") {
|
|
128872
|
+
return Buffer.byteLength(s2, "utf8");
|
|
128873
|
+
}
|
|
128874
|
+
if (typeof TextEncoder !== "undefined") {
|
|
128875
|
+
return new TextEncoder().encode(s2).length;
|
|
128876
|
+
}
|
|
128877
|
+
return s2.length;
|
|
128878
|
+
};
|
|
128879
|
+
if (maxSize !== undefined && computeBytes(input) > maxSize) {
|
|
128880
|
+
throw new McpError(-32007 /* ValidationError */, `JSON string exceeds maximum allowed size of ${maxSize} bytes.`, { actualSize: computeBytes(input), maxSize });
|
|
128881
|
+
}
|
|
128882
|
+
return JSON.parse(input);
|
|
128883
|
+
} catch (error48) {
|
|
128884
|
+
if (error48 instanceof McpError)
|
|
128885
|
+
throw error48;
|
|
128886
|
+
throw new McpError(-32007 /* ValidationError */, error48 instanceof Error ? error48.message : "Invalid JSON format.", {
|
|
128887
|
+
inputPreview: input.length > 100 ? `${input.substring(0, 100)}...` : input
|
|
128888
|
+
});
|
|
128889
|
+
}
|
|
128890
|
+
}
|
|
128891
|
+
sanitizeNumber(input, min, max) {
|
|
128892
|
+
let value;
|
|
128893
|
+
if (typeof input === "string") {
|
|
128894
|
+
const trimmedInput = input.trim();
|
|
128895
|
+
if (trimmedInput === "" || !import_validator.default.isNumeric(trimmedInput)) {
|
|
128896
|
+
throw new McpError(-32007 /* ValidationError */, "Invalid number format: input is empty or not numeric.", { input });
|
|
128897
|
+
}
|
|
128898
|
+
value = parseFloat(trimmedInput);
|
|
128899
|
+
} else if (typeof input === "number") {
|
|
128900
|
+
value = input;
|
|
128901
|
+
} else {
|
|
128902
|
+
throw new McpError(-32007 /* ValidationError */, "Invalid input type: expected number or string.", { input: String(input) });
|
|
128903
|
+
}
|
|
128904
|
+
if (isNaN(value) || !isFinite(value)) {
|
|
128905
|
+
throw new McpError(-32007 /* ValidationError */, "Invalid number value (NaN or Infinity).", { input });
|
|
128906
|
+
}
|
|
128907
|
+
let clamped = false;
|
|
128908
|
+
const originalValueForLog = value;
|
|
128909
|
+
if (min !== undefined && value < min) {
|
|
128910
|
+
value = min;
|
|
128911
|
+
clamped = true;
|
|
128912
|
+
}
|
|
128913
|
+
if (max !== undefined && value > max) {
|
|
128914
|
+
value = max;
|
|
128915
|
+
clamped = true;
|
|
128916
|
+
}
|
|
128917
|
+
if (clamped) {
|
|
128918
|
+
logger.debug("Number clamped to range.", requestContextService.createRequestContext({
|
|
128919
|
+
operation: "Sanitization.sanitizeNumber.clamped",
|
|
128920
|
+
additionalContext: {
|
|
128921
|
+
originalInput: String(input),
|
|
128922
|
+
parsedValue: originalValueForLog,
|
|
128923
|
+
minValue: min,
|
|
128924
|
+
maxValue: max,
|
|
128925
|
+
clampedValue: value
|
|
128926
|
+
}
|
|
128927
|
+
}));
|
|
128928
|
+
}
|
|
128929
|
+
return value;
|
|
128930
|
+
}
|
|
128931
|
+
sanitizeForLogging(input) {
|
|
128932
|
+
try {
|
|
128933
|
+
if (!input || typeof input !== "object")
|
|
128934
|
+
return input;
|
|
128935
|
+
const clonedInput = typeof globalThis.structuredClone === "function" ? globalThis.structuredClone(input) : JSON.parse(JSON.stringify(input));
|
|
128936
|
+
this.redactSensitiveFields(clonedInput);
|
|
128937
|
+
return clonedInput;
|
|
128938
|
+
} catch (error48) {
|
|
128939
|
+
logger.error("Error during log sanitization, returning placeholder.", requestContextService.createRequestContext({
|
|
128940
|
+
operation: "Sanitization.sanitizeForLogging.error",
|
|
128941
|
+
additionalContext: {
|
|
128942
|
+
errorMessage: error48 instanceof Error ? error48.message : String(error48)
|
|
128943
|
+
}
|
|
128944
|
+
}));
|
|
128945
|
+
return "[Log Sanitization Failed]";
|
|
128946
|
+
}
|
|
128947
|
+
}
|
|
128948
|
+
redactSensitiveFields(obj) {
|
|
128949
|
+
if (!obj || typeof obj !== "object")
|
|
128950
|
+
return;
|
|
128951
|
+
if (Array.isArray(obj)) {
|
|
128952
|
+
obj.forEach((item) => this.redactSensitiveFields(item));
|
|
128953
|
+
return;
|
|
128954
|
+
}
|
|
128955
|
+
const normalize = (str) => str.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
128956
|
+
const normalizedSensitiveSet = new Set(this.sensitiveFields.map((f3) => normalize(f3)).filter(Boolean));
|
|
128957
|
+
const wordSensitiveSet = new Set(this.sensitiveFields.map((f3) => f3.toLowerCase()).filter(Boolean));
|
|
128958
|
+
for (const key in obj) {
|
|
128959
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
128960
|
+
const value = obj[key];
|
|
128961
|
+
const normalizedKey = normalize(key);
|
|
128962
|
+
const keyWords = key.replace(/([A-Z])/g, " $1").toLowerCase().split(/[\s_-]+/).filter(Boolean);
|
|
128963
|
+
const isExactSensitive = normalizedSensitiveSet.has(normalizedKey);
|
|
128964
|
+
const isWordSensitive = keyWords.some((w) => wordSensitiveSet.has(w));
|
|
128965
|
+
const isSensitive = isExactSensitive || isWordSensitive;
|
|
128966
|
+
if (isSensitive) {
|
|
128967
|
+
obj[key] = "[REDACTED]";
|
|
128968
|
+
} else if (value && typeof value === "object") {
|
|
128969
|
+
this.redactSensitiveFields(value);
|
|
128970
|
+
}
|
|
128971
|
+
}
|
|
128972
|
+
}
|
|
128973
|
+
}
|
|
128974
|
+
}
|
|
128975
|
+
var sanitization = Sanitization.getInstance();
|
|
128976
|
+
var sanitizeInputForLogging = (input) => sanitization.sanitizeForLogging(input);
|
|
128977
|
+
|
|
128978
|
+
// src/utils/internal/logger.ts
|
|
128979
|
+
var mcpToPinoLevel = {
|
|
128980
|
+
emerg: "fatal",
|
|
128981
|
+
alert: "fatal",
|
|
128982
|
+
crit: "error",
|
|
128983
|
+
error: "error",
|
|
128984
|
+
warning: "warn",
|
|
128985
|
+
notice: "info",
|
|
128986
|
+
info: "info",
|
|
128987
|
+
debug: "debug"
|
|
128988
|
+
};
|
|
128989
|
+
var pinoToMcpLevelSeverity = {
|
|
128990
|
+
fatal: 0,
|
|
128991
|
+
error: 2,
|
|
128992
|
+
warn: 4,
|
|
128993
|
+
info: 6,
|
|
128994
|
+
debug: 7
|
|
128995
|
+
};
|
|
128996
|
+
var isServerless2 = typeof process === "undefined" || process.env.IS_SERVERLESS === "true";
|
|
128997
|
+
|
|
128998
|
+
class Logger {
|
|
128999
|
+
static instance = new Logger;
|
|
129000
|
+
pinoLogger;
|
|
129001
|
+
interactionLogger;
|
|
129002
|
+
initialized = false;
|
|
129003
|
+
currentMcpLevel = "info";
|
|
129004
|
+
transportType;
|
|
129005
|
+
rateLimitThreshold = 10;
|
|
129006
|
+
rateLimitWindow = 60000;
|
|
129007
|
+
messageCounts = new Map;
|
|
129008
|
+
suppressedMessages = new Map;
|
|
129009
|
+
cleanupTimer;
|
|
129010
|
+
constructor() {}
|
|
129011
|
+
static getInstance() {
|
|
129012
|
+
return Logger.instance;
|
|
129013
|
+
}
|
|
129014
|
+
async createPinoLogger(level, transportType) {
|
|
129015
|
+
const pinoLevel = mcpToPinoLevel[level] || "info";
|
|
129016
|
+
const pinoOptions = {
|
|
129017
|
+
level: pinoLevel,
|
|
129018
|
+
base: {
|
|
129019
|
+
env: config2.environment,
|
|
129020
|
+
version: config2.mcpServerVersion,
|
|
129021
|
+
pid: !isServerless2 ? process.pid : undefined
|
|
129022
|
+
},
|
|
129023
|
+
redact: {
|
|
129024
|
+
paths: sanitization.getSensitivePinoFields(),
|
|
129025
|
+
censor: "[REDACTED]"
|
|
129026
|
+
}
|
|
129027
|
+
};
|
|
129028
|
+
if (isServerless2) {
|
|
129029
|
+
return pino(pinoOptions);
|
|
129030
|
+
}
|
|
129031
|
+
const { default: fs2 } = await import("fs");
|
|
129032
|
+
const { default: path2 } = await import("path");
|
|
129033
|
+
const transports = [];
|
|
129034
|
+
const isDevelopment = config2.environment === "development";
|
|
129035
|
+
const isTest = config2.environment === "testing";
|
|
129036
|
+
const noColorEnv = process.env.NO_COLOR === "1" || process.env.FORCE_COLOR === "0";
|
|
129037
|
+
const useColoredOutput = isDevelopment && transportType !== "stdio" && !noColorEnv;
|
|
129038
|
+
if (useColoredOutput && !isServerless2) {
|
|
129039
|
+
try {
|
|
129040
|
+
const { createRequire: createRequire2 } = await import("node:module");
|
|
129041
|
+
const require2 = createRequire2(import.meta.url);
|
|
129042
|
+
const prettyTarget = require2.resolve("pino-pretty");
|
|
129043
|
+
transports.push({
|
|
129044
|
+
target: prettyTarget,
|
|
129045
|
+
options: { colorize: true, translateTime: "yyyy-mm-dd HH:MM:ss" }
|
|
129046
|
+
});
|
|
129047
|
+
} catch (err) {
|
|
129048
|
+
if (process.stderr?.isTTY) {
|
|
129049
|
+
console.warn(`[Logger Init] Pretty transport unavailable (${err instanceof Error ? err.message : String(err)}); falling back to stdout JSON.`);
|
|
129050
|
+
}
|
|
129051
|
+
transports.push({ target: "pino/file", options: { destination: 1 } });
|
|
129052
|
+
}
|
|
129053
|
+
} else if (!isTest) {
|
|
129054
|
+
transports.push({ target: "pino/file", options: { destination: 2 } });
|
|
129055
|
+
}
|
|
129056
|
+
if (config2.logsPath) {
|
|
129057
|
+
try {
|
|
129058
|
+
if (!fs2.existsSync(config2.logsPath)) {
|
|
129059
|
+
fs2.mkdirSync(config2.logsPath, { recursive: true });
|
|
129060
|
+
}
|
|
129061
|
+
transports.push({
|
|
129062
|
+
level: pinoLevel,
|
|
129063
|
+
target: "pino/file",
|
|
129064
|
+
options: {
|
|
129065
|
+
destination: path2.join(config2.logsPath, "combined.log"),
|
|
129066
|
+
mkdir: true
|
|
129067
|
+
}
|
|
129068
|
+
});
|
|
129069
|
+
transports.push({
|
|
129070
|
+
level: "error",
|
|
129071
|
+
target: "pino/file",
|
|
129072
|
+
options: {
|
|
129073
|
+
destination: path2.join(config2.logsPath, "error.log"),
|
|
129074
|
+
mkdir: true
|
|
129075
|
+
}
|
|
129076
|
+
});
|
|
129077
|
+
} catch (err) {
|
|
129078
|
+
if (process.stderr?.isTTY) {
|
|
129079
|
+
console.error(`[Logger Init] Failed to configure file logging: ${err instanceof Error ? err.message : String(err)}`);
|
|
129080
|
+
}
|
|
129081
|
+
}
|
|
129082
|
+
}
|
|
129083
|
+
return pino({ ...pinoOptions, transport: { targets: transports } });
|
|
129084
|
+
}
|
|
129085
|
+
async createInteractionLogger() {
|
|
129086
|
+
if (isServerless2 || !config2.logsPath)
|
|
129087
|
+
return;
|
|
129088
|
+
const { default: path2 } = await import("path");
|
|
129089
|
+
return pino({
|
|
129090
|
+
transport: {
|
|
129091
|
+
target: "pino/file",
|
|
129092
|
+
options: {
|
|
129093
|
+
destination: path2.join(config2.logsPath, "interactions.log"),
|
|
129094
|
+
mkdir: true
|
|
129095
|
+
}
|
|
129096
|
+
}
|
|
129097
|
+
});
|
|
129098
|
+
}
|
|
129099
|
+
async initialize(level = "info", transportType) {
|
|
129100
|
+
if (this.initialized) {
|
|
129101
|
+
this.warning("Logger already initialized.", requestContextService.createRequestContext({
|
|
129102
|
+
operation: "loggerReinit"
|
|
129103
|
+
}));
|
|
129104
|
+
return;
|
|
129105
|
+
}
|
|
129106
|
+
this.currentMcpLevel = level;
|
|
129107
|
+
this.transportType = transportType;
|
|
129108
|
+
this.pinoLogger = await this.createPinoLogger(level, transportType);
|
|
129109
|
+
this.interactionLogger = await this.createInteractionLogger();
|
|
129110
|
+
if (!isServerless2 && !this.cleanupTimer) {
|
|
129111
|
+
this.cleanupTimer = setInterval(() => this.flushSuppressedMessages(), this.rateLimitWindow);
|
|
129112
|
+
this.cleanupTimer.unref?.();
|
|
129113
|
+
}
|
|
129114
|
+
this.initialized = true;
|
|
129115
|
+
this.info(`Logger initialized. MCP level: ${level}.`, requestContextService.createRequestContext({ operation: "loggerInit" }));
|
|
129116
|
+
}
|
|
129117
|
+
setLevel(newLevel) {
|
|
129118
|
+
if (!this.pinoLogger || !this.initialized) {
|
|
129119
|
+
if (process.stderr?.isTTY) {
|
|
129120
|
+
console.error("Cannot set level: Logger not initialized.");
|
|
129121
|
+
}
|
|
129122
|
+
return;
|
|
129123
|
+
}
|
|
129124
|
+
this.currentMcpLevel = newLevel;
|
|
129125
|
+
this.pinoLogger.level = mcpToPinoLevel[newLevel] || "info";
|
|
129126
|
+
this.info(`Log level changed to ${newLevel}.`, requestContextService.createRequestContext({
|
|
129127
|
+
operation: "loggerSetLevel"
|
|
129128
|
+
}));
|
|
129129
|
+
}
|
|
129130
|
+
async close() {
|
|
129131
|
+
if (!this.initialized)
|
|
129132
|
+
return Promise.resolve();
|
|
129133
|
+
this.info("Logger shutting down.", requestContextService.createRequestContext({ operation: "loggerClose" }));
|
|
129134
|
+
if (this.cleanupTimer)
|
|
129135
|
+
clearInterval(this.cleanupTimer);
|
|
129136
|
+
this.flushSuppressedMessages();
|
|
129137
|
+
await Promise.all([
|
|
129138
|
+
new Promise((resolve) => {
|
|
129139
|
+
if (this.pinoLogger) {
|
|
129140
|
+
this.pinoLogger.flush((err) => {
|
|
129141
|
+
if (err && process.stderr?.isTTY && this.transportType !== "stdio") {
|
|
129142
|
+
console.error("Error flushing main logger:", err);
|
|
129143
|
+
}
|
|
129144
|
+
resolve();
|
|
129145
|
+
});
|
|
129146
|
+
} else {
|
|
129147
|
+
resolve();
|
|
129148
|
+
}
|
|
129149
|
+
}),
|
|
129150
|
+
new Promise((resolve) => {
|
|
129151
|
+
if (this.interactionLogger) {
|
|
129152
|
+
this.interactionLogger.flush((err) => {
|
|
129153
|
+
if (err && process.stderr?.isTTY && this.transportType !== "stdio") {
|
|
129154
|
+
console.error("Error flushing interaction logger:", err);
|
|
129155
|
+
}
|
|
129156
|
+
resolve();
|
|
129157
|
+
});
|
|
129158
|
+
} else {
|
|
129159
|
+
resolve();
|
|
129160
|
+
}
|
|
129161
|
+
})
|
|
129162
|
+
]);
|
|
129163
|
+
this.initialized = false;
|
|
129164
|
+
}
|
|
129165
|
+
isInitialized() {
|
|
129166
|
+
return this.initialized;
|
|
129167
|
+
}
|
|
129168
|
+
isRateLimited(message) {
|
|
129169
|
+
const now = Date.now();
|
|
129170
|
+
const entry = this.messageCounts.get(message);
|
|
129171
|
+
if (!entry) {
|
|
129172
|
+
this.messageCounts.set(message, { count: 1, firstSeen: now });
|
|
129173
|
+
return false;
|
|
129174
|
+
}
|
|
129175
|
+
if (now - entry.firstSeen > this.rateLimitWindow) {
|
|
129176
|
+
this.messageCounts.set(message, { count: 1, firstSeen: now });
|
|
129177
|
+
return false;
|
|
129178
|
+
}
|
|
129179
|
+
entry.count++;
|
|
129180
|
+
if (entry.count > this.rateLimitThreshold) {
|
|
129181
|
+
this.suppressedMessages.set(message, (this.suppressedMessages.get(message) || 0) + 1);
|
|
129182
|
+
return true;
|
|
129183
|
+
}
|
|
129184
|
+
return false;
|
|
129185
|
+
}
|
|
129186
|
+
flushSuppressedMessages() {
|
|
129187
|
+
if (this.suppressedMessages.size === 0)
|
|
129188
|
+
return;
|
|
129189
|
+
for (const [message, count] of this.suppressedMessages.entries()) {
|
|
129190
|
+
this.warning(`Log message suppressed ${count} times due to rate limiting.`, requestContextService.createRequestContext({
|
|
129191
|
+
operation: "loggerRateLimitFlush",
|
|
129192
|
+
additionalContext: { originalMessage: message }
|
|
129193
|
+
}));
|
|
129194
|
+
}
|
|
129195
|
+
this.suppressedMessages.clear();
|
|
129196
|
+
this.messageCounts.clear();
|
|
129197
|
+
}
|
|
129198
|
+
log(level, msg, context, error48) {
|
|
129199
|
+
if (!this.pinoLogger || !this.initialized)
|
|
129200
|
+
return;
|
|
129201
|
+
const pinoLevel = mcpToPinoLevel[level] || "info";
|
|
129202
|
+
const currentPinoLevel = mcpToPinoLevel[this.currentMcpLevel] || "info";
|
|
129203
|
+
const levelSeverity = pinoToMcpLevelSeverity[pinoLevel];
|
|
129204
|
+
const currentLevelSeverity = pinoToMcpLevelSeverity[currentPinoLevel];
|
|
129205
|
+
if (typeof levelSeverity === "number" && typeof currentLevelSeverity === "number" && levelSeverity > currentLevelSeverity) {
|
|
129206
|
+
return;
|
|
129207
|
+
}
|
|
129208
|
+
if (this.isRateLimited(msg))
|
|
129209
|
+
return;
|
|
129210
|
+
const logObject = { ...context };
|
|
129211
|
+
if (error48)
|
|
129212
|
+
logObject.err = pino.stdSerializers.err(error48);
|
|
129213
|
+
this.pinoLogger[pinoLevel](logObject, msg);
|
|
129214
|
+
}
|
|
129215
|
+
debug(msg, context) {
|
|
129216
|
+
this.log("debug", msg, context);
|
|
129217
|
+
}
|
|
129218
|
+
info(msg, context) {
|
|
129219
|
+
this.log("info", msg, context);
|
|
129220
|
+
}
|
|
129221
|
+
notice(msg, context) {
|
|
129222
|
+
this.log("notice", msg, context);
|
|
129223
|
+
}
|
|
129224
|
+
warning(msg, context) {
|
|
129225
|
+
this.log("warning", msg, context);
|
|
129226
|
+
}
|
|
129227
|
+
error(msg, errorOrContext, context) {
|
|
129228
|
+
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
129229
|
+
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
129230
|
+
this.log("error", msg, actualContext, errorObj);
|
|
129231
|
+
}
|
|
129232
|
+
crit(msg, errorOrContext, context) {
|
|
129233
|
+
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
129234
|
+
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
129235
|
+
this.log("crit", msg, actualContext, errorObj);
|
|
129236
|
+
}
|
|
129237
|
+
alert(msg, errorOrContext, context) {
|
|
129238
|
+
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
129239
|
+
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
129240
|
+
this.log("alert", msg, actualContext, errorObj);
|
|
129241
|
+
}
|
|
129242
|
+
emerg(msg, errorOrContext, context) {
|
|
129243
|
+
const errorObj = errorOrContext instanceof Error ? errorOrContext : undefined;
|
|
129244
|
+
const actualContext = errorOrContext instanceof Error ? context : errorOrContext;
|
|
129245
|
+
this.log("emerg", msg, actualContext, errorObj);
|
|
129246
|
+
}
|
|
129247
|
+
fatal(msg, errorOrContext, context) {
|
|
129248
|
+
this.emerg(msg, errorOrContext, context);
|
|
129249
|
+
}
|
|
129250
|
+
logInteraction(interactionName, data) {
|
|
129251
|
+
if (!this.interactionLogger) {
|
|
129252
|
+
if (!isServerless2)
|
|
129253
|
+
this.warning("Interaction logger not available.", data.context || {});
|
|
129254
|
+
return;
|
|
129255
|
+
}
|
|
129256
|
+
this.interactionLogger.info({ interactionName, ...data });
|
|
129257
|
+
}
|
|
129258
|
+
}
|
|
129259
|
+
var logger = Logger.getInstance();
|
|
129260
|
+
|
|
129261
|
+
// src/utils/internal/error-handler/mappings.ts
|
|
129262
|
+
var ERROR_TYPE_MAPPINGS = {
|
|
129263
|
+
SyntaxError: -32007 /* ValidationError */,
|
|
129264
|
+
TypeError: -32007 /* ValidationError */,
|
|
129265
|
+
ReferenceError: -32603 /* InternalError */,
|
|
129266
|
+
RangeError: -32007 /* ValidationError */,
|
|
129267
|
+
URIError: -32007 /* ValidationError */,
|
|
129268
|
+
EvalError: -32603 /* InternalError */,
|
|
129269
|
+
AggregateError: -32603 /* InternalError */
|
|
129270
|
+
};
|
|
129271
|
+
var COMMON_ERROR_PATTERNS = [
|
|
129272
|
+
{
|
|
129273
|
+
pattern: /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i,
|
|
129274
|
+
errorCode: -32006 /* Unauthorized */
|
|
129275
|
+
},
|
|
129276
|
+
{
|
|
129277
|
+
pattern: /permission|forbidden|access.*denied|not.*allowed/i,
|
|
129278
|
+
errorCode: -32005 /* Forbidden */
|
|
129279
|
+
},
|
|
129280
|
+
{
|
|
129281
|
+
pattern: /not found|missing|no such|doesn't exist|couldn't find/i,
|
|
129282
|
+
errorCode: -32001 /* NotFound */
|
|
129283
|
+
},
|
|
129284
|
+
{
|
|
129285
|
+
pattern: /invalid|validation|malformed|bad request|wrong format|missing required/i,
|
|
129286
|
+
errorCode: -32007 /* ValidationError */
|
|
129287
|
+
},
|
|
129288
|
+
{
|
|
129289
|
+
pattern: /conflict|already exists|duplicate|unique constraint/i,
|
|
129290
|
+
errorCode: -32002 /* Conflict */
|
|
129291
|
+
},
|
|
129292
|
+
{
|
|
129293
|
+
pattern: /rate limit|too many requests|throttled/i,
|
|
129294
|
+
errorCode: -32003 /* RateLimited */
|
|
129295
|
+
},
|
|
129296
|
+
{
|
|
129297
|
+
pattern: /timeout|timed out|deadline exceeded/i,
|
|
129298
|
+
errorCode: -32004 /* Timeout */
|
|
129299
|
+
},
|
|
129300
|
+
{
|
|
129301
|
+
pattern: /abort(ed)?|cancell?ed/i,
|
|
129302
|
+
errorCode: -32004 /* Timeout */
|
|
129303
|
+
},
|
|
129304
|
+
{
|
|
129305
|
+
pattern: /service unavailable|bad gateway|gateway timeout|upstream error/i,
|
|
129306
|
+
errorCode: -32000 /* ServiceUnavailable */
|
|
129307
|
+
},
|
|
129308
|
+
{
|
|
129309
|
+
pattern: /zod|zoderror|schema validation/i,
|
|
129310
|
+
errorCode: -32007 /* ValidationError */
|
|
129311
|
+
}
|
|
129312
|
+
];
|
|
129313
|
+
|
|
129314
|
+
// src/utils/internal/error-handler/helpers.ts
|
|
129315
|
+
function createSafeRegex(pattern) {
|
|
129316
|
+
if (pattern instanceof RegExp) {
|
|
129317
|
+
let flags = pattern.flags.replace("g", "");
|
|
129318
|
+
if (!flags.includes("i")) {
|
|
129319
|
+
flags += "i";
|
|
129320
|
+
}
|
|
129321
|
+
return new RegExp(pattern.source, flags);
|
|
129322
|
+
}
|
|
129323
|
+
return new RegExp(pattern, "i");
|
|
129324
|
+
}
|
|
129325
|
+
function getErrorName(error48) {
|
|
129326
|
+
if (error48 instanceof Error) {
|
|
129327
|
+
return error48.name || "Error";
|
|
129328
|
+
}
|
|
129329
|
+
if (error48 === null) {
|
|
129330
|
+
return "NullValueEncountered";
|
|
129331
|
+
}
|
|
129332
|
+
if (error48 === undefined) {
|
|
129333
|
+
return "UndefinedValueEncountered";
|
|
129334
|
+
}
|
|
129335
|
+
if (typeof error48 === "object" && error48 !== null && error48.constructor && typeof error48.constructor.name === "string" && error48.constructor.name !== "Object") {
|
|
129336
|
+
return `${error48.constructor.name}Encountered`;
|
|
129337
|
+
}
|
|
129338
|
+
return `${typeof error48}Encountered`;
|
|
129339
|
+
}
|
|
129340
|
+
function getErrorMessage(error48) {
|
|
129341
|
+
try {
|
|
129342
|
+
if (error48 instanceof Error) {
|
|
129343
|
+
if ("errors" in error48 && Array.isArray(error48.errors)) {
|
|
129344
|
+
const inner = error48.errors.map((e2) => e2 instanceof Error ? e2.message : String(e2)).filter(Boolean).slice(0, 3).join("; ");
|
|
129345
|
+
return inner ? `${error48.message}: ${inner}` : error48.message;
|
|
129346
|
+
}
|
|
129347
|
+
return error48.message;
|
|
129348
|
+
}
|
|
129349
|
+
if (error48 === null) {
|
|
129350
|
+
return "Null value encountered as error";
|
|
129351
|
+
}
|
|
129352
|
+
if (error48 === undefined) {
|
|
129353
|
+
return "Undefined value encountered as error";
|
|
129354
|
+
}
|
|
129355
|
+
if (typeof error48 === "string") {
|
|
129356
|
+
return error48;
|
|
129357
|
+
}
|
|
129358
|
+
if (typeof error48 === "number" || typeof error48 === "boolean") {
|
|
129359
|
+
return String(error48);
|
|
129360
|
+
}
|
|
129361
|
+
if (typeof error48 === "bigint") {
|
|
129362
|
+
return error48.toString();
|
|
129363
|
+
}
|
|
129364
|
+
if (typeof error48 === "function") {
|
|
129365
|
+
return `[function ${error48.name || "anonymous"}]`;
|
|
129366
|
+
}
|
|
129367
|
+
if (typeof error48 === "object") {
|
|
129368
|
+
try {
|
|
129369
|
+
const json2 = JSON.stringify(error48);
|
|
129370
|
+
if (json2 && json2 !== "{}")
|
|
129371
|
+
return json2;
|
|
129372
|
+
} catch {}
|
|
129373
|
+
const ctor = error48.constructor?.name;
|
|
129374
|
+
return `Non-Error object encountered (constructor: ${ctor || "Object"})`;
|
|
129375
|
+
}
|
|
129376
|
+
if (typeof error48 === "symbol") {
|
|
129377
|
+
return error48.toString();
|
|
129378
|
+
}
|
|
129379
|
+
return "[unrepresentable error]";
|
|
129380
|
+
} catch (conversionError) {
|
|
129381
|
+
return `Error converting error to string: ${conversionError instanceof Error ? conversionError.message : "Unknown conversion error"}`;
|
|
129382
|
+
}
|
|
129383
|
+
}
|
|
129384
|
+
|
|
129385
|
+
// src/utils/internal/error-handler/errorHandler.ts
|
|
129386
|
+
class ErrorHandler {
|
|
129387
|
+
static determineErrorCode(error48) {
|
|
129388
|
+
if (error48 instanceof McpError) {
|
|
129389
|
+
return error48.code;
|
|
129390
|
+
}
|
|
129391
|
+
const errorName = getErrorName(error48);
|
|
129392
|
+
const errorMessage = getErrorMessage(error48);
|
|
129393
|
+
const mappedFromType = ERROR_TYPE_MAPPINGS[errorName];
|
|
129394
|
+
if (mappedFromType) {
|
|
129395
|
+
return mappedFromType;
|
|
129396
|
+
}
|
|
129397
|
+
for (const mapping of COMMON_ERROR_PATTERNS) {
|
|
129398
|
+
const regex = createSafeRegex(mapping.pattern);
|
|
129399
|
+
if (regex.test(errorMessage) || regex.test(errorName)) {
|
|
129400
|
+
return mapping.errorCode;
|
|
129401
|
+
}
|
|
129402
|
+
}
|
|
129403
|
+
if (typeof error48 === "object" && error48 !== null && "name" in error48 && error48.name === "AbortError") {
|
|
129404
|
+
return -32004 /* Timeout */;
|
|
129405
|
+
}
|
|
129406
|
+
return -32603 /* InternalError */;
|
|
129407
|
+
}
|
|
129408
|
+
static handleError(error48, options) {
|
|
129409
|
+
const activeSpan = import_api3.trace.getActiveSpan();
|
|
129410
|
+
if (activeSpan) {
|
|
129411
|
+
if (error48 instanceof Error) {
|
|
129412
|
+
activeSpan.recordException(error48);
|
|
129413
|
+
}
|
|
129414
|
+
activeSpan.setStatus({
|
|
129415
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
129416
|
+
message: error48 instanceof Error ? error48.message : String(error48)
|
|
129417
|
+
});
|
|
129418
|
+
}
|
|
129419
|
+
const {
|
|
129420
|
+
context = {},
|
|
129421
|
+
operation,
|
|
129422
|
+
input,
|
|
129423
|
+
rethrow = false,
|
|
129424
|
+
errorCode: explicitErrorCode,
|
|
129425
|
+
includeStack = true,
|
|
129426
|
+
critical = false,
|
|
129427
|
+
errorMapper
|
|
129428
|
+
} = options;
|
|
129429
|
+
const sanitizedInput = input !== undefined ? sanitizeInputForLogging(input) : undefined;
|
|
129430
|
+
const originalErrorName = getErrorName(error48);
|
|
129431
|
+
const originalErrorMessage = getErrorMessage(error48);
|
|
129432
|
+
const originalStack = error48 instanceof Error ? error48.stack : undefined;
|
|
129433
|
+
let finalError;
|
|
129434
|
+
let loggedErrorCode;
|
|
129435
|
+
const errorDataSeed = error48 instanceof McpError && typeof error48.data === "object" && error48.data !== null ? { ...error48.data } : {};
|
|
129436
|
+
const consolidatedData = {
|
|
129437
|
+
...errorDataSeed,
|
|
129438
|
+
...context,
|
|
129439
|
+
originalErrorName,
|
|
129440
|
+
originalMessage: originalErrorMessage
|
|
129441
|
+
};
|
|
129442
|
+
if (originalStack && !(error48 instanceof McpError && error48.data?.originalStack)) {
|
|
129443
|
+
consolidatedData.originalStack = originalStack;
|
|
129444
|
+
}
|
|
129445
|
+
const cause = error48 instanceof Error ? error48 : undefined;
|
|
129446
|
+
const rootCause = (() => {
|
|
129447
|
+
let current = cause;
|
|
129448
|
+
let depth = 0;
|
|
129449
|
+
while (current && current instanceof Error && current.cause && depth < 5) {
|
|
129450
|
+
current = current.cause;
|
|
129451
|
+
depth += 1;
|
|
129452
|
+
}
|
|
129453
|
+
return current instanceof Error ? { name: current.name, message: current.message } : undefined;
|
|
129454
|
+
})();
|
|
129455
|
+
if (rootCause) {
|
|
129456
|
+
consolidatedData["rootCause"] = rootCause;
|
|
129457
|
+
}
|
|
129458
|
+
if (error48 instanceof McpError) {
|
|
129459
|
+
loggedErrorCode = error48.code;
|
|
129460
|
+
finalError = errorMapper ? errorMapper(error48) : new McpError(error48.code, error48.message, consolidatedData, {
|
|
129461
|
+
cause
|
|
129462
|
+
});
|
|
129463
|
+
} else {
|
|
129464
|
+
loggedErrorCode = explicitErrorCode || ErrorHandler.determineErrorCode(error48);
|
|
129465
|
+
const message = `Error in ${operation}: ${originalErrorMessage}`;
|
|
129466
|
+
finalError = errorMapper ? errorMapper(error48) : new McpError(loggedErrorCode, message, consolidatedData, {
|
|
129467
|
+
cause
|
|
129468
|
+
});
|
|
129469
|
+
}
|
|
129470
|
+
if (finalError !== error48 && error48 instanceof Error && finalError instanceof Error && !finalError.stack && error48.stack) {
|
|
129471
|
+
finalError.stack = error48.stack;
|
|
129472
|
+
}
|
|
129473
|
+
const logRequestId = typeof context.requestId === "string" && context.requestId ? context.requestId : generateUUID();
|
|
129474
|
+
const logTimestamp = typeof context.timestamp === "string" && context.timestamp ? context.timestamp : new Date().toISOString();
|
|
129475
|
+
const stack = finalError instanceof Error ? finalError.stack : originalStack;
|
|
129476
|
+
const logContext = {
|
|
129477
|
+
requestId: logRequestId,
|
|
129478
|
+
timestamp: logTimestamp,
|
|
129479
|
+
operation,
|
|
129480
|
+
input: sanitizedInput,
|
|
129481
|
+
critical,
|
|
129482
|
+
errorCode: loggedErrorCode,
|
|
129483
|
+
originalErrorType: originalErrorName,
|
|
129484
|
+
finalErrorType: getErrorName(finalError),
|
|
129485
|
+
...Object.fromEntries(Object.entries(context).filter(([key]) => key !== "requestId" && key !== "timestamp")),
|
|
129486
|
+
errorData: finalError instanceof McpError && finalError.data ? finalError.data : consolidatedData,
|
|
129487
|
+
...includeStack && stack ? { stack } : {}
|
|
129488
|
+
};
|
|
129489
|
+
logger.error(`Error in ${operation}: ${finalError.message || originalErrorMessage}`, logContext);
|
|
129490
|
+
if (rethrow) {
|
|
129491
|
+
throw finalError;
|
|
129492
|
+
}
|
|
129493
|
+
return finalError;
|
|
129494
|
+
}
|
|
129495
|
+
static mapError(error48, mappings, defaultFactory) {
|
|
129496
|
+
const errorMessage = getErrorMessage(error48);
|
|
129497
|
+
const errorName = getErrorName(error48);
|
|
129498
|
+
for (const mapping of mappings) {
|
|
129499
|
+
const regex = createSafeRegex(mapping.pattern);
|
|
129500
|
+
if (regex.test(errorMessage) || regex.test(errorName)) {
|
|
129501
|
+
return mapping.factory(error48, mapping.additionalContext);
|
|
129502
|
+
}
|
|
129503
|
+
}
|
|
129504
|
+
if (defaultFactory) {
|
|
129505
|
+
return defaultFactory(error48);
|
|
129506
|
+
}
|
|
129507
|
+
return error48 instanceof Error ? error48 : new Error(String(error48));
|
|
129508
|
+
}
|
|
129509
|
+
static formatError(error48) {
|
|
129510
|
+
if (error48 instanceof McpError) {
|
|
129511
|
+
return {
|
|
129512
|
+
code: error48.code,
|
|
129513
|
+
message: error48.message,
|
|
129514
|
+
data: typeof error48.data === "object" && error48.data !== null ? error48.data : {}
|
|
129515
|
+
};
|
|
129516
|
+
}
|
|
129517
|
+
if (error48 instanceof Error) {
|
|
129518
|
+
return {
|
|
129519
|
+
code: ErrorHandler.determineErrorCode(error48),
|
|
129520
|
+
message: error48.message,
|
|
129521
|
+
data: { errorType: error48.name || "Error" }
|
|
129522
|
+
};
|
|
129523
|
+
}
|
|
129524
|
+
return {
|
|
129525
|
+
code: -32099 /* UnknownError */,
|
|
129526
|
+
message: getErrorMessage(error48),
|
|
129527
|
+
data: { errorType: getErrorName(error48) }
|
|
129528
|
+
};
|
|
129529
|
+
}
|
|
129530
|
+
static async tryCatch(fn, options) {
|
|
129531
|
+
try {
|
|
129532
|
+
return await Promise.resolve(fn());
|
|
129533
|
+
} catch (caughtError) {
|
|
129534
|
+
throw ErrorHandler.handleError(caughtError, {
|
|
129535
|
+
...options,
|
|
129536
|
+
rethrow: true
|
|
129537
|
+
});
|
|
129538
|
+
}
|
|
129539
|
+
}
|
|
129540
|
+
}
|
|
129541
|
+
// src/utils/internal/runtime.ts
|
|
129542
|
+
var safeHas = (key) => {
|
|
129543
|
+
try {
|
|
129544
|
+
return typeof globalThis[key] !== "undefined";
|
|
129545
|
+
} catch {
|
|
129546
|
+
return false;
|
|
129547
|
+
}
|
|
129548
|
+
};
|
|
129549
|
+
var isBun = typeof globalThis.Bun !== "undefined" || typeof process.versions?.bun === "string";
|
|
129550
|
+
var isNode = !isBun && typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
129551
|
+
var hasProcess = typeof process !== "undefined";
|
|
129552
|
+
var hasBuffer = typeof Buffer !== "undefined";
|
|
129553
|
+
var hasTextEncoder = safeHas("TextEncoder");
|
|
129554
|
+
var hasPerformanceNow = typeof globalThis.performance?.now === "function";
|
|
129555
|
+
var isWorkerLike = !isNode && !isBun && typeof globalThis.WorkerGlobalScope !== "undefined";
|
|
129556
|
+
var isBrowserLike = !isNode && !isBun && !isWorkerLike && safeHas("window");
|
|
129557
|
+
var runtimeCaps = {
|
|
129558
|
+
isNode,
|
|
129559
|
+
isBun,
|
|
129560
|
+
isWorkerLike,
|
|
129561
|
+
isBrowserLike,
|
|
129562
|
+
hasProcess,
|
|
129563
|
+
hasBuffer,
|
|
129564
|
+
hasTextEncoder,
|
|
129565
|
+
hasPerformanceNow
|
|
129566
|
+
};
|
|
129567
|
+
function detectRuntime() {
|
|
129568
|
+
if (runtimeCaps.isBun) {
|
|
129569
|
+
return "bun";
|
|
129570
|
+
}
|
|
129571
|
+
if (runtimeCaps.isNode) {
|
|
129572
|
+
return "node";
|
|
129573
|
+
}
|
|
129574
|
+
if (runtimeCaps.isWorkerLike) {
|
|
129575
|
+
return "worker";
|
|
129576
|
+
}
|
|
129577
|
+
if (runtimeCaps.isBrowserLike) {
|
|
129578
|
+
return "browser";
|
|
129579
|
+
}
|
|
129580
|
+
return "unknown";
|
|
129581
|
+
}
|
|
129582
|
+
function getRuntimeDescription() {
|
|
129583
|
+
const runtime = detectRuntime();
|
|
129584
|
+
switch (runtime) {
|
|
129585
|
+
case "bun":
|
|
129586
|
+
return `Bun ${process.versions?.bun || "unknown"}`;
|
|
129587
|
+
case "node":
|
|
129588
|
+
return `Node.js ${process.versions?.node || "unknown"}`;
|
|
129589
|
+
case "worker":
|
|
129590
|
+
return "Cloudflare Workers / Web Worker";
|
|
129591
|
+
case "browser":
|
|
129592
|
+
return "Browser";
|
|
129593
|
+
default:
|
|
129594
|
+
return "Unknown runtime";
|
|
129595
|
+
}
|
|
129596
|
+
}
|
|
129597
|
+
|
|
129598
|
+
// src/utils/internal/performance.ts
|
|
129599
|
+
init_config();
|
|
129600
|
+
init_errors3();
|
|
129601
|
+
var import_api4 = __toESM(require_src(), 1);
|
|
129602
|
+
|
|
129603
|
+
// src/utils/telemetry/semconv.ts
|
|
129604
|
+
var ATTR_CODE_FUNCTION = "code.function";
|
|
129605
|
+
var ATTR_CODE_NAMESPACE = "code.namespace";
|
|
129606
|
+
var ATTR_MCP_TOOL_INPUT_BYTES = "mcp.tool.input_bytes";
|
|
129607
|
+
var ATTR_MCP_TOOL_OUTPUT_BYTES = "mcp.tool.output_bytes";
|
|
129608
|
+
var ATTR_MCP_TOOL_DURATION_MS = "mcp.tool.duration_ms";
|
|
129609
|
+
var ATTR_MCP_TOOL_SUCCESS = "mcp.tool.success";
|
|
129610
|
+
var ATTR_MCP_TOOL_ERROR_CODE = "mcp.tool.error_code";
|
|
129611
|
+
var ATTR_MCP_TOOL_MEMORY_RSS_BEFORE = "mcp.tool.memory_rss_bytes.before";
|
|
129612
|
+
var ATTR_MCP_TOOL_MEMORY_RSS_AFTER = "mcp.tool.memory_rss_bytes.after";
|
|
129613
|
+
var ATTR_MCP_TOOL_MEMORY_RSS_DELTA = "mcp.tool.memory_rss_bytes.delta";
|
|
129614
|
+
var ATTR_MCP_TOOL_MEMORY_HEAP_USED_BEFORE = "mcp.tool.memory_heap_used_bytes.before";
|
|
129615
|
+
var ATTR_MCP_TOOL_MEMORY_HEAP_USED_AFTER = "mcp.tool.memory_heap_used_bytes.after";
|
|
129616
|
+
var ATTR_MCP_TOOL_MEMORY_HEAP_USED_DELTA = "mcp.tool.memory_heap_used_bytes.delta";
|
|
129617
|
+
|
|
129618
|
+
// src/utils/internal/performance.ts
|
|
129619
|
+
var performanceNow = () => Date.now();
|
|
129620
|
+
async function loadPerfHooks() {
|
|
129621
|
+
return import("perf_hooks");
|
|
129622
|
+
}
|
|
129623
|
+
async function initializePerformance_Hrt() {
|
|
129624
|
+
const globalWithPerf = globalThis;
|
|
129625
|
+
if (typeof globalWithPerf.performance?.now === "function") {
|
|
129626
|
+
const perf = globalWithPerf.performance;
|
|
129627
|
+
performanceNow = () => perf?.now() ?? Date.now();
|
|
129628
|
+
} else {
|
|
129629
|
+
try {
|
|
129630
|
+
const { performance: nodePerformance } = await loadPerfHooks();
|
|
129631
|
+
performanceNow = () => nodePerformance.now();
|
|
129632
|
+
} catch (_e) {
|
|
129633
|
+
performanceNow = () => Date.now();
|
|
129634
|
+
logger.warning("Could not import perf_hooks, falling back to Date.now() for performance timing.");
|
|
129635
|
+
}
|
|
129636
|
+
}
|
|
129637
|
+
}
|
|
129638
|
+
var nowMs = () => performanceNow();
|
|
129639
|
+
var toBytes = (payload) => {
|
|
129640
|
+
if (payload == null)
|
|
129641
|
+
return 0;
|
|
129642
|
+
try {
|
|
129643
|
+
const json2 = JSON.stringify(payload);
|
|
129644
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function") {
|
|
129645
|
+
const bytes = Buffer.byteLength(json2, "utf8");
|
|
129646
|
+
return bytes;
|
|
129647
|
+
}
|
|
129648
|
+
if (typeof TextEncoder !== "undefined") {
|
|
129649
|
+
return new TextEncoder().encode(json2).length;
|
|
129650
|
+
}
|
|
129651
|
+
return json2.length;
|
|
129652
|
+
} catch {
|
|
129653
|
+
return 0;
|
|
129654
|
+
}
|
|
129655
|
+
};
|
|
129656
|
+
async function measureToolExecution(toolLogicFn, context, inputPayload) {
|
|
129657
|
+
const tracer = import_api4.trace.getTracer(config2.openTelemetry.serviceName, config2.openTelemetry.serviceVersion);
|
|
129658
|
+
const { toolName } = context;
|
|
129659
|
+
return tracer.startActiveSpan(`tool_execution:${toolName}`, async (span) => {
|
|
129660
|
+
const memBefore = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { rss: 0, heapUsed: 0 };
|
|
129661
|
+
const t0 = nowMs();
|
|
129662
|
+
span.setAttributes({
|
|
129663
|
+
[ATTR_CODE_FUNCTION]: toolName,
|
|
129664
|
+
[ATTR_CODE_NAMESPACE]: "mcp-tools",
|
|
129665
|
+
[ATTR_MCP_TOOL_INPUT_BYTES]: toBytes(inputPayload),
|
|
129666
|
+
[ATTR_MCP_TOOL_MEMORY_RSS_BEFORE]: memBefore.rss,
|
|
129667
|
+
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_BEFORE]: memBefore.heapUsed
|
|
129668
|
+
});
|
|
129669
|
+
let ok = false;
|
|
129670
|
+
let errorCode;
|
|
129671
|
+
let output;
|
|
129672
|
+
try {
|
|
129673
|
+
const result = await toolLogicFn();
|
|
129674
|
+
ok = true;
|
|
129675
|
+
output = result;
|
|
129676
|
+
span.setStatus({ code: import_api4.SpanStatusCode.OK });
|
|
129677
|
+
span.setAttribute(ATTR_MCP_TOOL_OUTPUT_BYTES, toBytes(output));
|
|
129678
|
+
return result;
|
|
129679
|
+
} catch (err) {
|
|
129680
|
+
if (err instanceof McpError)
|
|
129681
|
+
errorCode = String(err.code);
|
|
129682
|
+
else if (err instanceof Error)
|
|
129683
|
+
errorCode = "UNHANDLED_ERROR";
|
|
129684
|
+
else
|
|
129685
|
+
errorCode = "UNKNOWN_ERROR";
|
|
129686
|
+
if (err instanceof Error)
|
|
129687
|
+
span.recordException(err);
|
|
129688
|
+
span.setStatus({
|
|
129689
|
+
code: import_api4.SpanStatusCode.ERROR,
|
|
129690
|
+
message: err instanceof Error ? err.message : String(err)
|
|
129691
|
+
});
|
|
129692
|
+
throw err;
|
|
129693
|
+
} finally {
|
|
129694
|
+
const t1 = nowMs();
|
|
129695
|
+
const durationMs = Number((t1 - t0).toFixed(2));
|
|
129696
|
+
const memAfter = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { rss: 0, heapUsed: 0 };
|
|
129697
|
+
const rssDelta = memAfter.rss - memBefore.rss;
|
|
129698
|
+
const heapUsedDelta = memAfter.heapUsed - memBefore.heapUsed;
|
|
129699
|
+
span.setAttributes({
|
|
129700
|
+
[ATTR_MCP_TOOL_DURATION_MS]: durationMs,
|
|
129701
|
+
[ATTR_MCP_TOOL_SUCCESS]: ok,
|
|
129702
|
+
[ATTR_MCP_TOOL_MEMORY_RSS_AFTER]: memAfter.rss,
|
|
129703
|
+
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_AFTER]: memAfter.heapUsed,
|
|
129704
|
+
[ATTR_MCP_TOOL_MEMORY_RSS_DELTA]: rssDelta,
|
|
129705
|
+
[ATTR_MCP_TOOL_MEMORY_HEAP_USED_DELTA]: heapUsedDelta
|
|
129706
|
+
});
|
|
129707
|
+
if (errorCode)
|
|
129708
|
+
span.setAttribute(ATTR_MCP_TOOL_ERROR_CODE, errorCode);
|
|
129709
|
+
span.end();
|
|
129710
|
+
logger.info("Tool execution finished.", {
|
|
129711
|
+
...context,
|
|
129712
|
+
metrics: {
|
|
129713
|
+
durationMs,
|
|
129714
|
+
isSuccess: ok,
|
|
129715
|
+
errorCode,
|
|
129716
|
+
inputBytes: toBytes(inputPayload),
|
|
129717
|
+
outputBytes: toBytes(output),
|
|
129718
|
+
memory: {
|
|
129719
|
+
rss: {
|
|
129720
|
+
before: memBefore.rss,
|
|
129721
|
+
after: memAfter.rss,
|
|
129722
|
+
delta: rssDelta
|
|
129723
|
+
},
|
|
129724
|
+
heapUsed: {
|
|
129725
|
+
before: memBefore.heapUsed,
|
|
129726
|
+
after: memAfter.heapUsed,
|
|
129727
|
+
delta: heapUsedDelta
|
|
129728
|
+
}
|
|
129729
|
+
}
|
|
129730
|
+
}
|
|
129731
|
+
});
|
|
129732
|
+
}
|
|
129733
|
+
});
|
|
129734
|
+
}
|
|
129735
|
+
|
|
129736
|
+
// src/utils/internal/startupBanner.ts
|
|
129737
|
+
function logStartupBanner(message, transportType) {
|
|
129738
|
+
if (process.stdout.isTTY) {
|
|
129739
|
+
if (transportType === "stdio") {
|
|
129740
|
+
console.error(message);
|
|
129741
|
+
} else {
|
|
129742
|
+
console.log(message);
|
|
129743
|
+
}
|
|
129744
|
+
}
|
|
129745
|
+
}
|
|
129746
|
+
|
|
129747
|
+
// src/utils/security/idGenerator.ts
|
|
129748
|
+
init_errors3();
|
|
129749
|
+
import { randomUUID as cryptoRandomUUID, randomBytes } from "crypto";
|
|
129750
|
+
|
|
129751
|
+
class IdGenerator {
|
|
129752
|
+
static DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
129753
|
+
static DEFAULT_SEPARATOR = "_";
|
|
129754
|
+
static DEFAULT_LENGTH = 6;
|
|
129755
|
+
entityPrefixes = {};
|
|
129756
|
+
prefixToEntityType = {};
|
|
129757
|
+
constructor(entityPrefixes = {}) {
|
|
129758
|
+
this.setEntityPrefixes(entityPrefixes);
|
|
129759
|
+
}
|
|
129760
|
+
setEntityPrefixes(entityPrefixes) {
|
|
129761
|
+
this.entityPrefixes = { ...entityPrefixes };
|
|
129762
|
+
this.prefixToEntityType = Object.entries(this.entityPrefixes).reduce((acc, [type, prefix]) => {
|
|
129763
|
+
acc[prefix.toLowerCase()] = type;
|
|
129764
|
+
return acc;
|
|
129765
|
+
}, {});
|
|
129766
|
+
}
|
|
129767
|
+
getEntityPrefixes() {
|
|
129768
|
+
return { ...this.entityPrefixes };
|
|
129769
|
+
}
|
|
129770
|
+
generateRandomString(length = IdGenerator.DEFAULT_LENGTH, charset = IdGenerator.DEFAULT_CHARSET) {
|
|
129771
|
+
let result = "";
|
|
129772
|
+
const maxValidByteValue = Math.floor(256 / charset.length) * charset.length;
|
|
129773
|
+
while (result.length < length) {
|
|
129774
|
+
const byteBuffer = randomBytes(1);
|
|
129775
|
+
const byte = byteBuffer[0];
|
|
129776
|
+
if (byte !== undefined && byte < maxValidByteValue) {
|
|
129777
|
+
const charIndex = byte % charset.length;
|
|
129778
|
+
const char = charset[charIndex];
|
|
129779
|
+
if (char) {
|
|
129780
|
+
result += char;
|
|
129781
|
+
}
|
|
129782
|
+
}
|
|
129783
|
+
}
|
|
129784
|
+
return result;
|
|
129785
|
+
}
|
|
129786
|
+
generate(prefix, options = {}) {
|
|
129787
|
+
const {
|
|
129788
|
+
length = IdGenerator.DEFAULT_LENGTH,
|
|
129789
|
+
separator = IdGenerator.DEFAULT_SEPARATOR,
|
|
129790
|
+
charset = IdGenerator.DEFAULT_CHARSET
|
|
129791
|
+
} = options;
|
|
129792
|
+
const randomPart = this.generateRandomString(length, charset);
|
|
129793
|
+
const generatedId = prefix ? `${prefix}${separator}${randomPart}` : randomPart;
|
|
129794
|
+
return generatedId;
|
|
129795
|
+
}
|
|
129796
|
+
generateForEntity(entityType, options = {}) {
|
|
129797
|
+
const prefix = this.entityPrefixes[entityType];
|
|
129798
|
+
if (!prefix) {
|
|
129799
|
+
throw new McpError(-32007 /* ValidationError */, `Unknown entity type: ${entityType}. No prefix registered.`);
|
|
129800
|
+
}
|
|
129801
|
+
return this.generate(prefix, options);
|
|
129802
|
+
}
|
|
129803
|
+
isValid(id, entityType, options = {}) {
|
|
129804
|
+
const prefix = this.entityPrefixes[entityType];
|
|
129805
|
+
const {
|
|
129806
|
+
length = IdGenerator.DEFAULT_LENGTH,
|
|
129807
|
+
separator = IdGenerator.DEFAULT_SEPARATOR,
|
|
129808
|
+
charset = IdGenerator.DEFAULT_CHARSET
|
|
129809
|
+
} = options;
|
|
129810
|
+
if (!prefix) {
|
|
129811
|
+
return false;
|
|
129812
|
+
}
|
|
129813
|
+
const escapedCharsetForClass = charset.replace(/[[\]\\^-]/g, "\\$&");
|
|
129814
|
+
const charsetRegexPart = `[${escapedCharsetForClass}]`;
|
|
129815
|
+
const pattern = new RegExp(`^${this.escapeRegex(prefix)}${this.escapeRegex(separator)}${charsetRegexPart}{${length}}$`);
|
|
129816
|
+
return pattern.test(id);
|
|
129817
|
+
}
|
|
129818
|
+
escapeRegex(str) {
|
|
129819
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
129820
|
+
}
|
|
129821
|
+
stripPrefix(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
129822
|
+
const parts = id.split(separator);
|
|
129823
|
+
return parts.length > 1 ? parts.slice(1).join(separator) : id;
|
|
129824
|
+
}
|
|
129825
|
+
getEntityType(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
129826
|
+
const parts = id.split(separator);
|
|
129827
|
+
if (parts.length < 2 || !parts[0]) {
|
|
129828
|
+
throw new McpError(-32007 /* ValidationError */, `Invalid ID format: ${id}. Expected format like: PREFIX${separator}RANDOMLPART`);
|
|
129829
|
+
}
|
|
129830
|
+
const prefix = parts[0];
|
|
129831
|
+
const entityType = this.prefixToEntityType[prefix.toLowerCase()];
|
|
129832
|
+
if (!entityType) {
|
|
129833
|
+
throw new McpError(-32007 /* ValidationError */, `Unknown entity type for prefix: ${prefix}`);
|
|
129834
|
+
}
|
|
129835
|
+
return entityType;
|
|
129836
|
+
}
|
|
129837
|
+
normalize(id, separator = IdGenerator.DEFAULT_SEPARATOR) {
|
|
129838
|
+
const entityType = this.getEntityType(id, separator);
|
|
129839
|
+
const registeredPrefix = this.entityPrefixes[entityType];
|
|
129840
|
+
const idParts = id.split(separator);
|
|
129841
|
+
const randomPart = idParts.slice(1).join(separator);
|
|
129842
|
+
return `${registeredPrefix}${separator}${randomPart.toUpperCase()}`;
|
|
129843
|
+
}
|
|
129844
|
+
}
|
|
129845
|
+
var idGenerator = new IdGenerator;
|
|
129846
|
+
var generateUUID = () => {
|
|
129847
|
+
return cryptoRandomUUID();
|
|
129848
|
+
};
|
|
129849
|
+
var generateRequestContextId = () => {
|
|
129850
|
+
const generateSecureRandomString = (length, charset2) => {
|
|
129851
|
+
let result = "";
|
|
129852
|
+
const maxValidByteValue = Math.floor(256 / charset2.length) * charset2.length;
|
|
129853
|
+
while (result.length < length) {
|
|
129854
|
+
const byteBuffer = randomBytes(1);
|
|
129855
|
+
const byte = byteBuffer[0];
|
|
129856
|
+
if (byte !== undefined && byte < maxValidByteValue) {
|
|
129857
|
+
const charIndex = byte % charset2.length;
|
|
129858
|
+
const char = charset2[charIndex];
|
|
129859
|
+
if (char) {
|
|
129860
|
+
result += char;
|
|
129861
|
+
}
|
|
129862
|
+
}
|
|
129863
|
+
}
|
|
129864
|
+
return result;
|
|
129865
|
+
};
|
|
129866
|
+
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
129867
|
+
const part1 = generateSecureRandomString(5, charset);
|
|
129868
|
+
const part2 = generateSecureRandomString(5, charset);
|
|
129869
|
+
return `${part1}-${part2}`;
|
|
129870
|
+
};
|
|
129871
|
+
|
|
129872
|
+
// src/utils/security/rateLimiter.ts
|
|
129873
|
+
init_tokens();
|
|
129874
|
+
init_errors3();
|
|
129875
|
+
var import_api5 = __toESM(require_src(), 1);
|
|
129876
|
+
var import_tsyringe = __toESM(require_cjs2(), 1);
|
|
129877
|
+
class RateLimiter {
|
|
129878
|
+
config;
|
|
129879
|
+
logger;
|
|
129880
|
+
limits;
|
|
129881
|
+
cleanupTimer = null;
|
|
129882
|
+
effectiveConfig;
|
|
129883
|
+
constructor(config3, logger2) {
|
|
129884
|
+
this.config = config3;
|
|
129885
|
+
this.logger = logger2;
|
|
129886
|
+
const defaultConfig = {
|
|
129887
|
+
windowMs: 15 * 60 * 1000,
|
|
129888
|
+
maxRequests: 100,
|
|
129889
|
+
errorMessage: "Rate limit exceeded. Please try again in {waitTime} seconds.",
|
|
129890
|
+
skipInDevelopment: false,
|
|
129891
|
+
cleanupInterval: 5 * 60 * 1000
|
|
129892
|
+
};
|
|
129893
|
+
this.effectiveConfig = { ...defaultConfig };
|
|
129894
|
+
this.limits = new Map;
|
|
129895
|
+
this.startCleanupTimer();
|
|
129896
|
+
}
|
|
129897
|
+
startCleanupTimer() {
|
|
129898
|
+
if (this.cleanupTimer) {
|
|
129899
|
+
clearInterval(this.cleanupTimer);
|
|
129900
|
+
}
|
|
129901
|
+
const interval = this.effectiveConfig.cleanupInterval;
|
|
129902
|
+
if (interval && interval > 0) {
|
|
129903
|
+
this.cleanupTimer = setInterval(() => {
|
|
129904
|
+
this.cleanupExpiredEntries();
|
|
129905
|
+
}, interval);
|
|
129906
|
+
if (this.cleanupTimer.unref) {
|
|
129907
|
+
this.cleanupTimer.unref();
|
|
129908
|
+
}
|
|
129909
|
+
}
|
|
129910
|
+
}
|
|
129911
|
+
cleanupExpiredEntries() {
|
|
129912
|
+
const now = Date.now();
|
|
129913
|
+
let expiredCount = 0;
|
|
129914
|
+
for (const [key, entry] of this.limits.entries()) {
|
|
129915
|
+
if (now >= entry.resetTime) {
|
|
129916
|
+
this.limits.delete(key);
|
|
129917
|
+
expiredCount++;
|
|
129918
|
+
}
|
|
129919
|
+
}
|
|
129920
|
+
if (expiredCount > 0) {
|
|
129921
|
+
const logContext = requestContextService.createRequestContext({
|
|
129922
|
+
operation: "RateLimiter.cleanupExpiredEntries",
|
|
129923
|
+
additionalContext: {
|
|
129924
|
+
cleanedCount: expiredCount,
|
|
129925
|
+
totalRemainingAfterClean: this.limits.size
|
|
129926
|
+
}
|
|
129927
|
+
});
|
|
129928
|
+
this.logger.debug(`Cleaned up ${expiredCount} expired rate limit entries`, logContext);
|
|
129929
|
+
}
|
|
129930
|
+
}
|
|
129931
|
+
configure(config3) {
|
|
129932
|
+
Object.assign(this.effectiveConfig, config3);
|
|
129933
|
+
if (config3.cleanupInterval !== undefined) {
|
|
129934
|
+
this.startCleanupTimer();
|
|
129935
|
+
}
|
|
129936
|
+
}
|
|
129937
|
+
getConfig() {
|
|
129938
|
+
return { ...this.effectiveConfig };
|
|
129939
|
+
}
|
|
129940
|
+
reset() {
|
|
129941
|
+
this.limits.clear();
|
|
129942
|
+
const logContext = requestContextService.createRequestContext({
|
|
129943
|
+
operation: "RateLimiter.reset"
|
|
129944
|
+
});
|
|
129945
|
+
this.logger.debug("Rate limiter reset, all limits cleared", logContext);
|
|
129946
|
+
}
|
|
129947
|
+
check(key, context) {
|
|
129948
|
+
const activeSpan = import_api5.trace.getActiveSpan();
|
|
129949
|
+
activeSpan?.setAttribute("mcp.rate_limit.checked", true);
|
|
129950
|
+
if (this.effectiveConfig.skipInDevelopment && this.config.environment === "development") {
|
|
129951
|
+
activeSpan?.setAttribute("mcp.rate_limit.skipped", "development");
|
|
129952
|
+
return;
|
|
129953
|
+
}
|
|
129954
|
+
const limitKey = this.effectiveConfig.keyGenerator ? this.effectiveConfig.keyGenerator(key, context) : key;
|
|
129955
|
+
activeSpan?.setAttribute("mcp.rate_limit.key", limitKey);
|
|
129956
|
+
const now = Date.now();
|
|
129957
|
+
let entry = this.limits.get(limitKey);
|
|
129958
|
+
if (!entry || now >= entry.resetTime) {
|
|
129959
|
+
entry = {
|
|
129960
|
+
count: 1,
|
|
129961
|
+
resetTime: now + this.effectiveConfig.windowMs
|
|
129962
|
+
};
|
|
129963
|
+
this.limits.set(limitKey, entry);
|
|
129964
|
+
} else {
|
|
129965
|
+
entry.count++;
|
|
129966
|
+
}
|
|
129967
|
+
const remaining = Math.max(0, this.effectiveConfig.maxRequests - entry.count);
|
|
129968
|
+
activeSpan?.setAttributes({
|
|
129969
|
+
"mcp.rate_limit.limit": this.effectiveConfig.maxRequests,
|
|
129970
|
+
"mcp.rate_limit.count": entry.count,
|
|
129971
|
+
"mcp.rate_limit.remaining": remaining
|
|
129972
|
+
});
|
|
129973
|
+
if (entry.count > this.effectiveConfig.maxRequests) {
|
|
129974
|
+
const waitTime = Math.ceil((entry.resetTime - now) / 1000);
|
|
129975
|
+
const errorMessage = (this.effectiveConfig.errorMessage || "Rate limit exceeded. Please try again in {waitTime} seconds.").replace("{waitTime}", waitTime.toString());
|
|
129976
|
+
activeSpan?.addEvent("rate_limit_exceeded", {
|
|
129977
|
+
"mcp.rate_limit.wait_time_seconds": waitTime
|
|
129978
|
+
});
|
|
129979
|
+
throw new McpError(-32003 /* RateLimited */, errorMessage, {
|
|
129980
|
+
waitTimeSeconds: waitTime,
|
|
129981
|
+
key: limitKey,
|
|
129982
|
+
limit: this.effectiveConfig.maxRequests,
|
|
129983
|
+
windowMs: this.effectiveConfig.windowMs
|
|
129984
|
+
});
|
|
129985
|
+
}
|
|
129986
|
+
}
|
|
129987
|
+
getStatus(key) {
|
|
129988
|
+
const entry = this.limits.get(key);
|
|
129989
|
+
if (!entry)
|
|
129990
|
+
return null;
|
|
129991
|
+
return {
|
|
129992
|
+
current: entry.count,
|
|
129993
|
+
limit: this.effectiveConfig.maxRequests,
|
|
129994
|
+
remaining: Math.max(0, this.effectiveConfig.maxRequests - entry.count),
|
|
129995
|
+
resetTime: entry.resetTime
|
|
129996
|
+
};
|
|
129997
|
+
}
|
|
129998
|
+
dispose() {
|
|
129999
|
+
if (this.cleanupTimer) {
|
|
130000
|
+
clearInterval(this.cleanupTimer);
|
|
130001
|
+
this.cleanupTimer = null;
|
|
130002
|
+
}
|
|
130003
|
+
this.limits.clear();
|
|
130004
|
+
}
|
|
130005
|
+
}
|
|
130006
|
+
RateLimiter = __legacyDecorateClassTS([
|
|
130007
|
+
import_tsyringe.injectable(),
|
|
130008
|
+
__legacyDecorateParamTS(0, import_tsyringe.inject(AppConfig)),
|
|
130009
|
+
__legacyDecorateParamTS(1, import_tsyringe.inject(Logger2)),
|
|
130010
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
130011
|
+
Object,
|
|
130012
|
+
Object
|
|
130013
|
+
])
|
|
130014
|
+
], RateLimiter);
|
|
130297
130015
|
|
|
130298
130016
|
// src/container/index.ts
|
|
130299
130017
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
@@ -132754,13 +132472,8 @@ if (shouldShowDeprecationWarning())
|
|
|
132754
132472
|
init_config();
|
|
132755
132473
|
init_tokens();
|
|
132756
132474
|
|
|
132757
|
-
// src/services/git/core/GitProviderFactory.ts
|
|
132758
|
-
init_utils();
|
|
132759
|
-
|
|
132760
132475
|
// src/services/git/core/BaseGitProvider.ts
|
|
132761
132476
|
init_errors3();
|
|
132762
|
-
init_utils();
|
|
132763
|
-
|
|
132764
132477
|
class BaseGitProvider {
|
|
132765
132478
|
checkCapability(capability) {
|
|
132766
132479
|
if (!this.capabilities[capability]) {
|
|
@@ -132794,12 +132507,12 @@ class BaseGitProvider {
|
|
|
132794
132507
|
workingDirectory
|
|
132795
132508
|
});
|
|
132796
132509
|
}
|
|
132797
|
-
createOperationContext(
|
|
132510
|
+
createOperationContext(requestContext, workingDirectory, tenantId) {
|
|
132798
132511
|
const context = {
|
|
132799
|
-
requestContext
|
|
132512
|
+
requestContext,
|
|
132800
132513
|
workingDirectory
|
|
132801
132514
|
};
|
|
132802
|
-
const finalTenantId = tenantId ||
|
|
132515
|
+
const finalTenantId = tenantId || requestContext.tenantId;
|
|
132803
132516
|
if (finalTenantId) {
|
|
132804
132517
|
context.tenantId = finalTenantId;
|
|
132805
132518
|
}
|
|
@@ -133185,8 +132898,8 @@ Stdout: ${stdout}`;
|
|
|
133185
132898
|
});
|
|
133186
132899
|
}
|
|
133187
132900
|
async function spawnGitCommand(args, cwd, env, timeout = 60000, signal, allowNonZeroExit = false) {
|
|
133188
|
-
const
|
|
133189
|
-
if (
|
|
132901
|
+
const runtime = detectRuntime2();
|
|
132902
|
+
if (runtime === "bun") {
|
|
133190
132903
|
return spawnWithBun(args, cwd, env, timeout, signal, allowNonZeroExit);
|
|
133191
132904
|
} else {
|
|
133192
132905
|
return spawnWithNode(args, cwd, env, timeout, signal, allowNonZeroExit);
|
|
@@ -133258,6 +132971,15 @@ function parseGitStatus(output) {
|
|
|
133258
132971
|
const parts2 = line.split(" ");
|
|
133259
132972
|
if (parts2[1] === "branch.head" && parts2[2]) {
|
|
133260
132973
|
result.currentBranch = parts2[2] === "(detached)" ? null : parts2[2];
|
|
132974
|
+
} else if (parts2[1] === "branch.upstream" && parts2[2]) {
|
|
132975
|
+
result.upstream = parts2[2];
|
|
132976
|
+
} else if (parts2[1] === "branch.ab" && parts2[2] && parts2[3]) {
|
|
132977
|
+
const ahead = parseInt(parts2[2].replace(/^\+/, ""), 10);
|
|
132978
|
+
const behind = parseInt(parts2[3].replace(/^-/, ""), 10);
|
|
132979
|
+
if (Number.isFinite(ahead))
|
|
132980
|
+
result.ahead = ahead;
|
|
132981
|
+
if (Number.isFinite(behind))
|
|
132982
|
+
result.behind = behind;
|
|
133261
132983
|
}
|
|
133262
132984
|
continue;
|
|
133263
132985
|
}
|
|
@@ -133677,8 +133399,10 @@ async function executeCommit(options, context, execGit) {
|
|
|
133677
133399
|
if (options.noVerify) {
|
|
133678
133400
|
args.push("--no-verify");
|
|
133679
133401
|
}
|
|
133680
|
-
const
|
|
133681
|
-
|
|
133402
|
+
const signRequested = shouldSignCommits();
|
|
133403
|
+
let signed = false;
|
|
133404
|
+
let signingWarning;
|
|
133405
|
+
if (signRequested) {
|
|
133682
133406
|
args.push("--gpg-sign");
|
|
133683
133407
|
}
|
|
133684
133408
|
if (options.author) {
|
|
@@ -133688,17 +133412,20 @@ async function executeCommit(options, context, execGit) {
|
|
|
133688
133412
|
const cmd = buildGitCommand({ command: "commit", args });
|
|
133689
133413
|
try {
|
|
133690
133414
|
await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
133415
|
+
signed = signRequested;
|
|
133691
133416
|
} catch (error48) {
|
|
133692
|
-
if (
|
|
133693
|
-
const unsignedArgs = args.filter((a) => a !== "--gpg-sign");
|
|
133694
|
-
const unsignedCmd = buildGitCommand({
|
|
133695
|
-
command: "commit",
|
|
133696
|
-
args: unsignedArgs
|
|
133697
|
-
});
|
|
133698
|
-
await execGit(unsignedCmd, context.workingDirectory, context.requestContext);
|
|
133699
|
-
} else {
|
|
133417
|
+
if (!signRequested) {
|
|
133700
133418
|
throw error48;
|
|
133701
133419
|
}
|
|
133420
|
+
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
133421
|
+
logger.warning("Commit signing failed; retrying unsigned. Set GIT_SIGN_COMMITS=false to suppress this attempt.", { ...context.requestContext, error: error48 });
|
|
133422
|
+
signingWarning = `GIT_SIGN_COMMITS is enabled but signing failed; commit created unsigned. Check signing key availability (gpg-agent running, SSH key accessible). Underlying error: ${errorMessage}`;
|
|
133423
|
+
const unsignedArgs = args.filter((a) => a !== "--gpg-sign");
|
|
133424
|
+
const unsignedCmd = buildGitCommand({
|
|
133425
|
+
command: "commit",
|
|
133426
|
+
args: unsignedArgs
|
|
133427
|
+
});
|
|
133428
|
+
await execGit(unsignedCmd, context.workingDirectory, context.requestContext);
|
|
133702
133429
|
}
|
|
133703
133430
|
const hashCmd = buildGitCommand({
|
|
133704
133431
|
command: "rev-parse",
|
|
@@ -133727,8 +133454,12 @@ async function executeCommit(options, context, execGit) {
|
|
|
133727
133454
|
message: options.message,
|
|
133728
133455
|
author: authorName,
|
|
133729
133456
|
timestamp,
|
|
133730
|
-
filesChanged
|
|
133457
|
+
filesChanged,
|
|
133458
|
+
signed
|
|
133731
133459
|
};
|
|
133460
|
+
if (signingWarning) {
|
|
133461
|
+
result.signingWarning = signingWarning;
|
|
133462
|
+
}
|
|
133732
133463
|
return result;
|
|
133733
133464
|
} catch (error48) {
|
|
133734
133465
|
throw mapGitError(error48, "commit");
|
|
@@ -133739,7 +133470,9 @@ var COMMIT_START_MARKER = "<<<COMMIT_START>>>";
|
|
|
133739
133470
|
var COMMIT_END_MARKER = "<<<COMMIT_END>>>";
|
|
133740
133471
|
async function executeLog(options, context, execGit) {
|
|
133741
133472
|
try {
|
|
133742
|
-
const
|
|
133473
|
+
const fullFormat = `${COMMIT_START_MARKER}%H${GIT_FIELD_DELIMITER}%h${GIT_FIELD_DELIMITER}%an${GIT_FIELD_DELIMITER}%ae${GIT_FIELD_DELIMITER}%at${GIT_FIELD_DELIMITER}%s${GIT_FIELD_DELIMITER}%b${GIT_FIELD_DELIMITER}%P${COMMIT_END_MARKER}`;
|
|
133474
|
+
const onelineFormat = `${COMMIT_START_MARKER}%H${GIT_FIELD_DELIMITER}%h${GIT_FIELD_DELIMITER}%s${COMMIT_END_MARKER}`;
|
|
133475
|
+
const formatStr = options.oneline ? onelineFormat : fullFormat;
|
|
133743
133476
|
const args = [`--format=${formatStr}`];
|
|
133744
133477
|
if (options.maxCount) {
|
|
133745
133478
|
args.push(`-n${options.maxCount}`);
|
|
@@ -133782,7 +133515,11 @@ async function executeLog(options, context, execGit) {
|
|
|
133782
133515
|
const formatPart = section.substring(0, endIdx);
|
|
133783
133516
|
const extraPart = section.substring(endIdx + COMMIT_END_MARKER.length).trim();
|
|
133784
133517
|
const fields = formatPart.split(GIT_FIELD_DELIMITER);
|
|
133785
|
-
const commit = {
|
|
133518
|
+
const commit = options.oneline ? {
|
|
133519
|
+
hash: fields[0] || "",
|
|
133520
|
+
shortHash: fields[1] || "",
|
|
133521
|
+
subject: fields[2] || ""
|
|
133522
|
+
} : {
|
|
133786
133523
|
hash: fields[0] || "",
|
|
133787
133524
|
shortHash: fields[1] || "",
|
|
133788
133525
|
author: fields[2] || "",
|
|
@@ -133791,7 +133528,7 @@ async function executeLog(options, context, execGit) {
|
|
|
133791
133528
|
subject: fields[5] || "",
|
|
133792
133529
|
parents: (fields[7] || "").split(" ").filter((p) => p)
|
|
133793
133530
|
};
|
|
133794
|
-
if (fields[6]) {
|
|
133531
|
+
if (!options.oneline && fields[6]) {
|
|
133795
133532
|
commit.body = fields[6];
|
|
133796
133533
|
}
|
|
133797
133534
|
if (extraPart) {
|
|
@@ -133839,11 +133576,13 @@ async function executeShow(options, context, execGit) {
|
|
|
133839
133576
|
command: "cat-file",
|
|
133840
133577
|
args: ["-t", options.object]
|
|
133841
133578
|
});
|
|
133842
|
-
const
|
|
133579
|
+
const cmd = buildGitCommand({ command: "show", args });
|
|
133580
|
+
const [typeResult, result] = await Promise.all([
|
|
133581
|
+
execGit(typeCmd, context.workingDirectory, context.requestContext),
|
|
133582
|
+
execGit(cmd, context.workingDirectory, context.requestContext)
|
|
133583
|
+
]);
|
|
133843
133584
|
const detectedType = typeResult.stdout.trim();
|
|
133844
133585
|
const objectType = ["commit", "tree", "blob", "tag"].includes(detectedType) ? detectedType : "commit";
|
|
133845
|
-
const cmd = buildGitCommand({ command: "show", args });
|
|
133846
|
-
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
133847
133586
|
const showResult = {
|
|
133848
133587
|
object: options.object,
|
|
133849
133588
|
type: objectType,
|
|
@@ -134039,6 +133778,21 @@ async function executeBranch(options, context, execGit) {
|
|
|
134039
133778
|
try {
|
|
134040
133779
|
const args = [];
|
|
134041
133780
|
switch (options.mode) {
|
|
133781
|
+
case "show-current": {
|
|
133782
|
+
const cmd = buildGitCommand({
|
|
133783
|
+
command: "symbolic-ref",
|
|
133784
|
+
args: ["--quiet", "--short", "HEAD"]
|
|
133785
|
+
});
|
|
133786
|
+
try {
|
|
133787
|
+
const res = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
133788
|
+
return {
|
|
133789
|
+
mode: "show-current",
|
|
133790
|
+
current: res.stdout.trim() || null
|
|
133791
|
+
};
|
|
133792
|
+
} catch {
|
|
133793
|
+
return { mode: "show-current", current: null };
|
|
133794
|
+
}
|
|
133795
|
+
}
|
|
134042
133796
|
case "list": {
|
|
134043
133797
|
const format = [
|
|
134044
133798
|
"%(refname)",
|
|
@@ -134057,6 +133811,9 @@ async function executeBranch(options, context, execGit) {
|
|
|
134057
133811
|
const noMergedRef = typeof options.noMerged === "string" ? options.noMerged : "HEAD";
|
|
134058
133812
|
args.push(`--no-merged=${noMergedRef}`);
|
|
134059
133813
|
}
|
|
133814
|
+
if (typeof options.limit === "number" && options.limit > 0) {
|
|
133815
|
+
args.push(`--count=${options.limit}`);
|
|
133816
|
+
}
|
|
134060
133817
|
const cmd = buildGitCommand({ command: "for-each-ref", args });
|
|
134061
133818
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
134062
133819
|
const branches = parseBranchRef(result.stdout);
|
|
@@ -134185,8 +133942,7 @@ async function executeMerge(options, context, execGit) {
|
|
|
134185
133942
|
if (options.message) {
|
|
134186
133943
|
args.push("-m", options.message);
|
|
134187
133944
|
}
|
|
134188
|
-
|
|
134189
|
-
if (shouldSign) {
|
|
133945
|
+
if (shouldSignCommits()) {
|
|
134190
133946
|
args.push("-S");
|
|
134191
133947
|
}
|
|
134192
133948
|
args.push(options.branch);
|
|
@@ -134283,8 +134039,7 @@ ${continueResult.stderr}`),
|
|
|
134283
134039
|
if (options.preserve) {
|
|
134284
134040
|
args.push("--preserve-merges");
|
|
134285
134041
|
}
|
|
134286
|
-
|
|
134287
|
-
if (shouldSign) {
|
|
134042
|
+
if (shouldSignCommits()) {
|
|
134288
134043
|
args.push("--gpg-sign");
|
|
134289
134044
|
}
|
|
134290
134045
|
if (options.onto) {
|
|
@@ -134366,8 +134121,7 @@ async function executeCherryPick(options, context, execGit) {
|
|
|
134366
134121
|
if (options.signoff) {
|
|
134367
134122
|
args.push("--signoff");
|
|
134368
134123
|
}
|
|
134369
|
-
|
|
134370
|
-
if (shouldSign) {
|
|
134124
|
+
if (shouldSignCommits()) {
|
|
134371
134125
|
args.push("--gpg-sign");
|
|
134372
134126
|
}
|
|
134373
134127
|
args.push(...options.commits);
|
|
@@ -134643,6 +134397,9 @@ async function executePull(options, context, execGit) {
|
|
|
134643
134397
|
if (options.fastForwardOnly) {
|
|
134644
134398
|
args.push("--ff-only");
|
|
134645
134399
|
}
|
|
134400
|
+
if (shouldSignCommits()) {
|
|
134401
|
+
args.push("-S");
|
|
134402
|
+
}
|
|
134646
134403
|
const cmd = buildGitCommand({ command: "pull", args });
|
|
134647
134404
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext, { allowNonZeroExit: true });
|
|
134648
134405
|
const hasConflicts = result.stdout.includes("CONFLICT") || result.stderr.includes("CONFLICT");
|
|
@@ -134707,17 +134464,26 @@ async function executeTag(options, context, execGit) {
|
|
|
134707
134464
|
"%(if)%(*objectname:short)%(then)%(*objectname:short)%(else)%(objectname:short)%(end)",
|
|
134708
134465
|
"%(if)%(contents:subject)%(then)%(contents:subject)%(end)",
|
|
134709
134466
|
"%(if)%(taggername)%(then)%(taggername) %(taggeremail)%(end)",
|
|
134710
|
-
"%(if)%(creatordate:unix)%(then)%(creatordate:unix)%(end)"
|
|
134711
|
-
|
|
134467
|
+
"%(if)%(creatordate:unix)%(then)%(creatordate:unix)%(end)",
|
|
134468
|
+
"%(if)%(contents:body)%(then)%(contents:body)%(end)"
|
|
134469
|
+
].join(GIT_FIELD_DELIMITER) + GIT_RECORD_DELIMITER;
|
|
134470
|
+
const forEachRefArgs = [
|
|
134471
|
+
`--format=${format}`,
|
|
134472
|
+
"--sort=-version:refname",
|
|
134473
|
+
"--sort=-creatordate"
|
|
134474
|
+
];
|
|
134475
|
+
if (typeof options.limit === "number" && options.limit > 0) {
|
|
134476
|
+
forEachRefArgs.push(`--count=${options.limit}`);
|
|
134477
|
+
}
|
|
134478
|
+
forEachRefArgs.push("refs/tags");
|
|
134712
134479
|
const refCmd = buildGitCommand({
|
|
134713
134480
|
command: "for-each-ref",
|
|
134714
|
-
args:
|
|
134481
|
+
args: forEachRefArgs
|
|
134715
134482
|
});
|
|
134716
134483
|
const result = await execGit(refCmd, context.workingDirectory, context.requestContext);
|
|
134717
134484
|
const tags = [];
|
|
134718
|
-
for (const
|
|
134719
|
-
|
|
134720
|
-
const [name, commit, message, tagger, timestamp] = line.split(GIT_FIELD_DELIMITER);
|
|
134485
|
+
for (const record2 of result.stdout.split(GIT_RECORD_DELIMITER).map((r2) => r2.replace(/^\n/, "")).filter((r2) => r2.length > 0)) {
|
|
134486
|
+
const [name, commit, message, tagger, timestamp, annotationBody] = record2.split(GIT_FIELD_DELIMITER);
|
|
134721
134487
|
if (!name)
|
|
134722
134488
|
continue;
|
|
134723
134489
|
const tag = {
|
|
@@ -134730,6 +134496,8 @@ async function executeTag(options, context, execGit) {
|
|
|
134730
134496
|
tag.tagger = tagger;
|
|
134731
134497
|
if (timestamp)
|
|
134732
134498
|
tag.timestamp = parseInt(timestamp, 10);
|
|
134499
|
+
if (annotationBody)
|
|
134500
|
+
tag.annotationBody = annotationBody.trimEnd();
|
|
134733
134501
|
tags.push(tag);
|
|
134734
134502
|
}
|
|
134735
134503
|
return { mode: "list", tags };
|
|
@@ -134738,7 +134506,9 @@ async function executeTag(options, context, execGit) {
|
|
|
134738
134506
|
if (!options.tagName) {
|
|
134739
134507
|
throw new Error("Tag name is required for create operation");
|
|
134740
134508
|
}
|
|
134741
|
-
const
|
|
134509
|
+
const signRequested = shouldSignCommits();
|
|
134510
|
+
let signed = false;
|
|
134511
|
+
let signingWarning;
|
|
134742
134512
|
const buildCreateArgs = (sign) => {
|
|
134743
134513
|
const createArgs = [options.tagName];
|
|
134744
134514
|
if (sign) {
|
|
@@ -134757,31 +134527,36 @@ async function executeTag(options, context, execGit) {
|
|
|
134757
134527
|
}
|
|
134758
134528
|
return createArgs;
|
|
134759
134529
|
};
|
|
134760
|
-
const
|
|
134761
|
-
|
|
134762
|
-
|
|
134763
|
-
|
|
134764
|
-
|
|
134765
|
-
|
|
134766
|
-
|
|
134767
|
-
|
|
134530
|
+
const buildCmd = (sign) => {
|
|
134531
|
+
const configOverride = sign ? [] : ["-c", "tag.gpgSign=false"];
|
|
134532
|
+
return [
|
|
134533
|
+
...configOverride,
|
|
134534
|
+
...buildGitCommand({
|
|
134535
|
+
command: "tag",
|
|
134536
|
+
args: buildCreateArgs(sign)
|
|
134537
|
+
})
|
|
134538
|
+
];
|
|
134539
|
+
};
|
|
134768
134540
|
try {
|
|
134769
|
-
await execGit(
|
|
134541
|
+
await execGit(buildCmd(signRequested), context.workingDirectory, context.requestContext);
|
|
134542
|
+
signed = signRequested;
|
|
134770
134543
|
} catch (error48) {
|
|
134771
|
-
if (
|
|
134772
|
-
const unsignedCmd = buildGitCommand({
|
|
134773
|
-
command: "tag",
|
|
134774
|
-
args: buildCreateArgs(false)
|
|
134775
|
-
});
|
|
134776
|
-
await execGit(unsignedCmd, context.workingDirectory, context.requestContext);
|
|
134777
|
-
} else {
|
|
134544
|
+
if (!signRequested) {
|
|
134778
134545
|
throw error48;
|
|
134779
134546
|
}
|
|
134547
|
+
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
134548
|
+
logger.warning("Tag signing failed; retrying unsigned. Set GIT_SIGN_COMMITS=false to suppress this attempt.", { ...context.requestContext, error: error48 });
|
|
134549
|
+
signingWarning = `GIT_SIGN_COMMITS is enabled but signing failed; tag created unsigned. Check signing key availability (gpg-agent running, SSH key accessible). Underlying error: ${errorMessage}`;
|
|
134550
|
+
await execGit(buildCmd(false), context.workingDirectory, context.requestContext);
|
|
134780
134551
|
}
|
|
134781
134552
|
const createResult = {
|
|
134782
134553
|
mode: "create",
|
|
134783
|
-
created: options.tagName
|
|
134554
|
+
created: options.tagName,
|
|
134555
|
+
signed
|
|
134784
134556
|
};
|
|
134557
|
+
if (signingWarning) {
|
|
134558
|
+
createResult.signingWarning = signingWarning;
|
|
134559
|
+
}
|
|
134785
134560
|
return createResult;
|
|
134786
134561
|
}
|
|
134787
134562
|
case "delete": {
|
|
@@ -134811,6 +134586,9 @@ async function executeStash(options, context, execGit) {
|
|
|
134811
134586
|
switch (options.mode) {
|
|
134812
134587
|
case "list": {
|
|
134813
134588
|
args.push("--format=%gd\t%ct\t%gs");
|
|
134589
|
+
if (typeof options.limit === "number" && options.limit > 0) {
|
|
134590
|
+
args.push(`-n${options.limit}`);
|
|
134591
|
+
}
|
|
134814
134592
|
const cmd = buildGitCommand({ command: "stash", args });
|
|
134815
134593
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
134816
134594
|
const stashes = result.stdout.split(`
|
|
@@ -135527,7 +135305,6 @@ var import_tsyringe4 = __toESM(require_cjs2(), 1);
|
|
|
135527
135305
|
|
|
135528
135306
|
// src/storage/providers/fileSystem/fileSystemProvider.ts
|
|
135529
135307
|
init_errors3();
|
|
135530
|
-
init_utils();
|
|
135531
135308
|
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
135532
135309
|
import { readFile, readdir, rm, writeFile } from "fs/promises";
|
|
135533
135310
|
import path2 from "path";
|
|
@@ -135762,7 +135539,6 @@ class FileSystemProvider {
|
|
|
135762
135539
|
}
|
|
135763
135540
|
|
|
135764
135541
|
// src/storage/providers/inMemory/inMemoryProvider.ts
|
|
135765
|
-
init_utils();
|
|
135766
135542
|
var DEFAULT_LIST_LIMIT2 = 1000;
|
|
135767
135543
|
|
|
135768
135544
|
class InMemoryProvider {
|
|
@@ -135875,7 +135651,6 @@ class InMemoryProvider {
|
|
|
135875
135651
|
// src/storage/providers/supabase/supabaseProvider.ts
|
|
135876
135652
|
var import_tsyringe3 = __toESM(require_cjs2(), 1);
|
|
135877
135653
|
init_tokens();
|
|
135878
|
-
init_utils();
|
|
135879
135654
|
var TABLE_NAME = "kv_store";
|
|
135880
135655
|
var DEFAULT_LIST_LIMIT3 = 1000;
|
|
135881
135656
|
|
|
@@ -136045,7 +135820,6 @@ SupabaseProvider = __legacyDecorateClassTS([
|
|
|
136045
135820
|
|
|
136046
135821
|
// src/storage/providers/cloudflare/r2Provider.ts
|
|
136047
135822
|
init_errors3();
|
|
136048
|
-
init_utils();
|
|
136049
135823
|
var R2_ENVELOPE_VERSION = 1;
|
|
136050
135824
|
var DEFAULT_LIST_LIMIT4 = 1000;
|
|
136051
135825
|
|
|
@@ -136241,7 +136015,6 @@ class R2Provider {
|
|
|
136241
136015
|
|
|
136242
136016
|
// src/storage/providers/cloudflare/kvProvider.ts
|
|
136243
136017
|
init_errors3();
|
|
136244
|
-
init_utils();
|
|
136245
136018
|
var DEFAULT_LIST_LIMIT5 = 1000;
|
|
136246
136019
|
|
|
136247
136020
|
class KvProvider {
|
|
@@ -136408,7 +136181,6 @@ class KvProvider {
|
|
|
136408
136181
|
}
|
|
136409
136182
|
|
|
136410
136183
|
// src/storage/core/storageFactory.ts
|
|
136411
|
-
init_utils();
|
|
136412
136184
|
var isServerless3 = typeof process === "undefined" || process.env.IS_SERVERLESS === "true";
|
|
136413
136185
|
function createStorageProvider(config3, deps = {}) {
|
|
136414
136186
|
const context = requestContextService.createRequestContext({
|
|
@@ -136457,8 +136229,6 @@ function createStorageProvider(config3, deps = {}) {
|
|
|
136457
136229
|
|
|
136458
136230
|
// src/container/registrations/core.ts
|
|
136459
136231
|
init_errors3();
|
|
136460
|
-
init_utils();
|
|
136461
|
-
init_rateLimiter();
|
|
136462
136232
|
var registerCoreServices = () => {
|
|
136463
136233
|
const config3 = parseConfig();
|
|
136464
136234
|
import_tsyringe5.container.register(AppConfig, { useValue: config3 });
|
|
@@ -136500,12 +136270,9 @@ var import_tsyringe6 = __toESM(require_cjs2(), 1);
|
|
|
136500
136270
|
|
|
136501
136271
|
// src/mcp-server/resources/definitions/git-working-directory.resource.ts
|
|
136502
136272
|
init_zod();
|
|
136503
|
-
init_utils();
|
|
136504
136273
|
|
|
136505
136274
|
// src/mcp-server/transports/auth/lib/authUtils.ts
|
|
136506
136275
|
init_errors3();
|
|
136507
|
-
init_utils();
|
|
136508
|
-
init_authContext();
|
|
136509
136276
|
function withRequiredScopes(requiredScopes) {
|
|
136510
136277
|
const operationName = "withRequiredScopesCheck";
|
|
136511
136278
|
const initialContext = requestContextService.createRequestContext({
|
|
@@ -145125,7 +144892,6 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
145125
144892
|
|
|
145126
144893
|
// src/mcp-server/resources/utils/resourceHandlerFactory.ts
|
|
145127
144894
|
init_errors3();
|
|
145128
|
-
init_utils();
|
|
145129
144895
|
function defaultResponseFormatter(result, meta3) {
|
|
145130
144896
|
return [
|
|
145131
144897
|
{
|
|
@@ -145211,7 +144977,6 @@ async function registerResource(server, def) {
|
|
|
145211
144977
|
}
|
|
145212
144978
|
|
|
145213
144979
|
// src/mcp-server/resources/resource-registration.ts
|
|
145214
|
-
init_utils();
|
|
145215
144980
|
class ResourceRegistry {
|
|
145216
144981
|
resourceDefs;
|
|
145217
144982
|
constructor(resourceDefs) {
|
|
@@ -145251,12 +145016,10 @@ var import_tsyringe7 = __toESM(require_cjs2(), 1);
|
|
|
145251
145016
|
// src/mcp-server/prompts/definitions/git-wrapup.prompt.ts
|
|
145252
145017
|
init_zod();
|
|
145253
145018
|
var PROMPT_NAME = "git_wrapup";
|
|
145254
|
-
var PROMPT_DESCRIPTION = "
|
|
145019
|
+
var PROMPT_DESCRIPTION = "Orchestrates a full git wrap-up: loads the project-aware acceptance-criteria protocol from git_wrapup_instructions, analyzes changes, satisfies each criterion per project convention, commits atomically, and (optionally) tags the release.";
|
|
145255
145020
|
var ArgumentsSchema = exports_external.object({
|
|
145256
|
-
changelogPath: exports_external.string().optional().describe("Path to the changelog file
|
|
145257
|
-
|
|
145258
|
-
createTag: exports_external.string().optional().describe("Whether to create a git tag after committing ('true' | 'false'). Defaults to 'false'."),
|
|
145259
|
-
updateAgentFiles: exports_external.string().optional().describe("Whether to update agent meta files like CLAUDE.md, AGENTS.md ('true' | 'false'). Defaults to 'false'.")
|
|
145021
|
+
changelogPath: exports_external.string().optional().describe("Path to the changelog file when the project uses a flat one (defaults to CHANGELOG.md). The protocol itself defers to project convention."),
|
|
145022
|
+
createTag: exports_external.string().optional().describe("Whether to include the tag criterion in the protocol ('true' | 'false'). Defaults to 'true' — set to 'false' when tagging is deferred to a separate release step.")
|
|
145260
145023
|
});
|
|
145261
145024
|
var gitWrapupPrompt = {
|
|
145262
145025
|
name: PROMPT_NAME,
|
|
@@ -145264,57 +145027,34 @@ var gitWrapupPrompt = {
|
|
|
145264
145027
|
argumentsSchema: ArgumentsSchema,
|
|
145265
145028
|
generate: (args) => {
|
|
145266
145029
|
const changelogPath = args.changelogPath || "CHANGELOG.md";
|
|
145267
|
-
const
|
|
145268
|
-
const createTag = args.createTag === "true";
|
|
145269
|
-
const updateAgentFiles = args.updateAgentFiles === "true";
|
|
145270
|
-
const documentationSection = skipDocumentation ? "" : `
|
|
145271
|
-
4. **Review Documentation**: Read the README.md file and verify it accurately reflects the current codebase state. Update as necessary to maintain currency and accuracy.
|
|
145272
|
-
`;
|
|
145273
|
-
const agentFilesSection = updateAgentFiles ? `
|
|
145274
|
-
5. **Update Agent Files**: If present, review and update agent-specific meta files (CLAUDE.md, AGENTS.md, .clinerules/) to reflect any architectural or protocol changes.
|
|
145275
|
-
` : "";
|
|
145276
|
-
const tagSection = createTag ? `
|
|
145277
|
-
After all commits are complete and verified via git_status, create an annotated git tag using the git_tag tool. Use semantic versioning (e.g., v1.2.3) and include a summary of key changes in the annotation message.
|
|
145278
|
-
` : "";
|
|
145030
|
+
const includeTag = args.createTag !== "false";
|
|
145279
145031
|
return [
|
|
145280
145032
|
{
|
|
145281
145033
|
role: "user",
|
|
145282
145034
|
content: {
|
|
145283
145035
|
type: "text",
|
|
145284
|
-
text: `You are an expert git workflow manager.
|
|
145036
|
+
text: `You are an expert git workflow manager. Run a complete wrap-up for the current git session.
|
|
145285
145037
|
|
|
145286
|
-
##
|
|
145038
|
+
## Session Flow
|
|
145287
145039
|
|
|
145288
|
-
|
|
145040
|
+
1. **Load Protocol**: Call \`git_wrapup_instructions\` with \`acknowledgement: "yes"\`${includeTag ? "" : " and `createTag: false`"}. It returns an acceptance-criteria checklist — every box must be satisfied before the wrap-up is complete — plus the current repository status.
|
|
145289
145041
|
|
|
145290
|
-
|
|
145042
|
+
2. **Set Working Directory**: If not already set, call \`git_set_working_dir\` to establish the session context. Required before any git operations.
|
|
145291
145043
|
|
|
145292
|
-
|
|
145044
|
+
3. **Analyze Changes**: Run \`git_diff\` with \`includeUntracked: true\`. Understand the "why" behind every modification end-to-end before grouping anything — the diff drives your commit plan and messages.
|
|
145293
145045
|
|
|
145294
|
-
|
|
145046
|
+
4. **Satisfy the Acceptance Criteria**: Work each checkbox from step 1. The protocol is strict on outcomes, generic on mechanism — follow this project's own conventions for where versions live, how the changelog is formatted (default path when flat: \`${changelogPath}\`), and what the verification suite looks like. If the root agent-instruction file (\`AGENTS.md\`, \`CLAUDE.md\`, or equivalent) documents a project-specific wrap-up procedure, that takes precedence over the generic checklist.
|
|
145295
145047
|
|
|
145296
|
-
|
|
145297
|
-
- Uses past tense and concise language
|
|
145298
|
-
- Categorizes changes (Added, Changed, Fixed, Deprecated, Removed, Security)
|
|
145299
|
-
- Follows the existing changelog format
|
|
145300
|
-
- Provides enough detail for users to understand the impact
|
|
145301
|
-
${documentationSection}${agentFilesSection}
|
|
145302
|
-
5. **Commit Changes**: Use \`git_commit\` to create atomic, logical commits. For each commit:
|
|
145303
|
-
- Group related changes together using the \`filesToStage\` parameter
|
|
145304
|
-
- Write commit messages following Conventional Commits format (e.g., \`feat(auth): add password reset\`, \`fix(parser): handle edge case\`)
|
|
145305
|
-
- Ensure commits are self-contained and buildable
|
|
145306
|
-
- Do not mix unrelated changes in a single commit
|
|
145048
|
+
5. **Commit Atomically**: Use \`git_commit\` to create logical, self-contained commits in Conventional Commits form. Group related changes with the \`filesToStage\` parameter. No mixing unrelated changes in one commit.
|
|
145307
145049
|
|
|
145308
|
-
6. **Verify
|
|
145309
|
-
${tagSection}
|
|
145310
|
-
## Important Guidelines
|
|
145050
|
+
6. **Verify Clean**: Run \`git_status\` to confirm the working tree is clean and every change is committed.${includeTag ? "\n\n7. **Tag the Release**: Create an annotated git tag with `git_tag` using semantic versioning (e.g., `v1.2.3`). The annotation message should summarize the real changes — no filler." : ""}
|
|
145311
145051
|
|
|
145312
|
-
|
|
145313
|
-
|
|
145314
|
-
-
|
|
145315
|
-
-
|
|
145316
|
-
-
|
|
145317
|
-
-
|
|
145052
|
+
## Constraints
|
|
145053
|
+
|
|
145054
|
+
- **Do not push** to the remote unless explicitly instructed.
|
|
145055
|
+
- Create a task list before starting so progress is trackable.
|
|
145056
|
+
- Do not bypass verification failures to land a green commit.
|
|
145057
|
+
- On merge conflicts or unexpected errors: stop and surface the blocker.
|
|
145318
145058
|
|
|
145319
145059
|
Begin by calling \`git_wrapup_instructions\` and creating your task list.`
|
|
145320
145060
|
}
|
|
@@ -145327,11 +145067,10 @@ Begin by calling \`git_wrapup_instructions\` and creating your task list.`
|
|
|
145327
145067
|
var allPromptDefinitions = [gitWrapupPrompt];
|
|
145328
145068
|
|
|
145329
145069
|
// src/mcp-server/prompts/prompt-registration.ts
|
|
145330
|
-
init_utils();
|
|
145331
145070
|
class PromptRegistry {
|
|
145332
145071
|
logger;
|
|
145333
|
-
constructor(
|
|
145334
|
-
this.logger =
|
|
145072
|
+
constructor(logger2) {
|
|
145073
|
+
this.logger = logger2;
|
|
145335
145074
|
}
|
|
145336
145075
|
registerAll(server) {
|
|
145337
145076
|
const context = requestContextService.createRequestContext({
|
|
@@ -145364,7 +145103,6 @@ PromptRegistry = __legacyDecorateClassTS([
|
|
|
145364
145103
|
|
|
145365
145104
|
// src/mcp-server/tools/tool-registration.ts
|
|
145366
145105
|
var import_tsyringe9 = __toESM(require_cjs2(), 1);
|
|
145367
|
-
init_utils();
|
|
145368
145106
|
|
|
145369
145107
|
// src/mcp-server/tools/definitions/git-changelog-analyze.tool.ts
|
|
145370
145108
|
init_zod();
|
|
@@ -145403,7 +145141,6 @@ var AllSchema = exports_external.boolean().default(false).describe("Include all
|
|
|
145403
145141
|
var MergeStrategySchema = exports_external.enum(["ort", "recursive", "octopus", "ours", "subtree"]).optional().describe("Merge strategy to use (ort, recursive, octopus, ours, subtree).");
|
|
145404
145142
|
var PruneSchema = exports_external.boolean().default(false).describe("Prune remote-tracking references that no longer exist on remote.");
|
|
145405
145143
|
var DepthSchema = exports_external.number().int().min(1).optional().describe("Create a shallow clone with history truncated to N commits.");
|
|
145406
|
-
var SignSchema = exports_external.boolean().optional().describe("Sign the commit/tag with GPG/SSH. Omit to use the server's GIT_SIGN_COMMITS default (recommended). Set true to force signing, or false to skip signing even when the default enables it.");
|
|
145407
145144
|
var NoVerifySchema = exports_external.boolean().default(false).describe("Bypass pre-commit and commit-msg hooks.");
|
|
145408
145145
|
|
|
145409
145146
|
// src/mcp-server/tools/utils/json-response-formatter.ts
|
|
@@ -145527,12 +145264,10 @@ var defaultJsonFormatter = createJsonFormatter();
|
|
|
145527
145264
|
|
|
145528
145265
|
// src/mcp-server/tools/utils/toolHandlerFactory.ts
|
|
145529
145266
|
init_tokens();
|
|
145530
|
-
init_utils();
|
|
145531
145267
|
var import_tsyringe8 = __toESM(require_cjs2(), 1);
|
|
145532
145268
|
|
|
145533
145269
|
// src/mcp-server/tools/utils/git-validators.ts
|
|
145534
145270
|
init_errors3();
|
|
145535
|
-
init_utils();
|
|
145536
145271
|
import path3 from "node:path";
|
|
145537
145272
|
async function resolveWorkingDirectory(pathInput, appContext, storage) {
|
|
145538
145273
|
let workingDir;
|
|
@@ -145805,6 +145540,7 @@ var InputSchema = exports_external.object({
|
|
|
145805
145540
|
path: PathSchema,
|
|
145806
145541
|
reviewTypes: exports_external.array(ReviewTypeSchema).min(1).describe("Types of changelog review to perform. At least one required. Options: security, features, storyline, gaps, breaking_changes, quality."),
|
|
145807
145542
|
maxCommits: exports_external.number().int().min(1).max(1000).default(200).describe("Maximum recent commits to fetch for cross-referencing (1-1000)."),
|
|
145543
|
+
maxTags: exports_external.number().int().min(1).max(1000).default(100).describe("Maximum recent tags to fetch for release context (1-1000). Applied at the git command so large tag catalogs do not bloat the response."),
|
|
145808
145544
|
sinceTag: exports_external.string().optional().describe('Only include git history since this tag (e.g., "v1.2.0"). Narrows the analysis window.'),
|
|
145809
145545
|
branch: CommitRefSchema.optional().describe("Branch to analyze (defaults to current branch).")
|
|
145810
145546
|
});
|
|
@@ -145857,7 +145593,7 @@ async function gitChangelogAnalyzeLogic(input, { provider, targetPath, appContex
|
|
|
145857
145593
|
}
|
|
145858
145594
|
const [logResult, tagResult, statusResult] = await Promise.all([
|
|
145859
145595
|
provider.log(logOptions, operationContext),
|
|
145860
|
-
provider.tag({ mode: "list" }, operationContext),
|
|
145596
|
+
provider.tag({ mode: "list", limit: input.maxTags }, operationContext),
|
|
145861
145597
|
provider.status({ includeUntracked: false }, operationContext)
|
|
145862
145598
|
]);
|
|
145863
145599
|
const reviewInstructions = buildReviewInstructions(input.reviewTypes);
|
|
@@ -145870,8 +145606,8 @@ async function gitChangelogAnalyzeLogic(input, { provider, targetPath, appContex
|
|
|
145870
145606
|
commits: logResult.commits.map((c) => ({
|
|
145871
145607
|
hash: c.shortHash,
|
|
145872
145608
|
subject: c.subject,
|
|
145873
|
-
author: c.author,
|
|
145874
|
-
timestamp: c.timestamp,
|
|
145609
|
+
author: c.author ?? "",
|
|
145610
|
+
timestamp: c.timestamp ?? 0,
|
|
145875
145611
|
...c.refs && c.refs.length > 0 && { refs: c.refs }
|
|
145876
145612
|
})),
|
|
145877
145613
|
tags: (tagResult.tags ?? []).map((t2) => ({
|
|
@@ -146300,162 +146036,246 @@ var gitReflogTool = {
|
|
|
146300
146036
|
|
|
146301
146037
|
// src/mcp-server/tools/definitions/git-set-working-dir.tool.ts
|
|
146302
146038
|
init_zod();
|
|
146039
|
+
init_errors3();
|
|
146040
|
+
|
|
146041
|
+
// src/mcp-server/tools/utils/repo-snapshot.ts
|
|
146042
|
+
init_zod();
|
|
146043
|
+
var RepoSnapshotStatusSchema = exports_external.object({
|
|
146044
|
+
branch: exports_external.string().nullable().describe("Current branch (null on detached HEAD)."),
|
|
146045
|
+
isClean: exports_external.boolean().describe("True when the working tree has no changes."),
|
|
146046
|
+
staged: exports_external.array(exports_external.string()).describe("Paths staged for the next commit."),
|
|
146047
|
+
unstaged: exports_external.array(exports_external.string()).describe("Paths with unstaged modifications."),
|
|
146048
|
+
untracked: exports_external.array(exports_external.string()).describe("Untracked paths."),
|
|
146049
|
+
conflicts: exports_external.array(exports_external.string()).describe("Paths with merge conflicts."),
|
|
146050
|
+
upstream: exports_external.string().optional().describe("Upstream ref being tracked by the current branch."),
|
|
146051
|
+
ahead: exports_external.number().int().optional().describe("Commits ahead of upstream (if tracking)."),
|
|
146052
|
+
behind: exports_external.number().int().optional().describe("Commits behind upstream (if tracking).")
|
|
146053
|
+
});
|
|
146054
|
+
var RepoSnapshotCommitSchema = exports_external.object({
|
|
146055
|
+
hash: exports_external.string().describe("Short commit hash."),
|
|
146056
|
+
author: exports_external.string().describe("Author name."),
|
|
146057
|
+
date: exports_external.string().describe("Author date (ISO 8601)."),
|
|
146058
|
+
subject: exports_external.string().describe("First line of the commit message.")
|
|
146059
|
+
});
|
|
146060
|
+
var RepoSnapshotTagSchema = exports_external.object({
|
|
146061
|
+
name: exports_external.string().describe("Tag name."),
|
|
146062
|
+
date: exports_external.string().optional().describe("Creator date (ISO 8601); absent for lightweight tags with no metadata."),
|
|
146063
|
+
tagger: exports_external.string().optional().describe("Tagger identity (annotated tags only)."),
|
|
146064
|
+
annotationSubject: exports_external.string().optional().describe("First line of the tag annotation (annotated tags only)."),
|
|
146065
|
+
annotationBody: exports_external.string().optional().describe("Remaining annotation body after the subject (annotated tags only).")
|
|
146066
|
+
});
|
|
146067
|
+
var RepoSnapshotRemoteSchema = exports_external.object({
|
|
146068
|
+
name: exports_external.string().describe("Remote name."),
|
|
146069
|
+
fetchUrl: exports_external.string().describe("Fetch URL."),
|
|
146070
|
+
pushUrl: exports_external.string().describe("Push URL (may differ from fetch URL).")
|
|
146071
|
+
});
|
|
146072
|
+
var NOT_A_REPO_HINT = "Repository snapshot unavailable — the path may not be a git repository. Initialize it via git_init or point at an existing repo.";
|
|
146073
|
+
function reasonMessage(reason) {
|
|
146074
|
+
if (reason instanceof Error)
|
|
146075
|
+
return reason.message;
|
|
146076
|
+
if (typeof reason === "string")
|
|
146077
|
+
return reason;
|
|
146078
|
+
if (reason === null || reason === undefined)
|
|
146079
|
+
return "unknown error";
|
|
146080
|
+
try {
|
|
146081
|
+
return JSON.stringify(reason);
|
|
146082
|
+
} catch {
|
|
146083
|
+
return "unknown error";
|
|
146084
|
+
}
|
|
146085
|
+
}
|
|
146086
|
+
function isNotARepoError(reason) {
|
|
146087
|
+
if (!reason)
|
|
146088
|
+
return false;
|
|
146089
|
+
return /not a git repository/i.test(reasonMessage(reason));
|
|
146090
|
+
}
|
|
146091
|
+
function isEmptyRepoError(reason) {
|
|
146092
|
+
if (!reason)
|
|
146093
|
+
return false;
|
|
146094
|
+
return /does not have any commits yet/i.test(reasonMessage(reason));
|
|
146095
|
+
}
|
|
146096
|
+
function toIsoDate(unixSeconds) {
|
|
146097
|
+
if (typeof unixSeconds !== "number" || !Number.isFinite(unixSeconds)) {
|
|
146098
|
+
return;
|
|
146099
|
+
}
|
|
146100
|
+
return new Date(unixSeconds * 1000).toISOString();
|
|
146101
|
+
}
|
|
146102
|
+
async function gatherRepoSnapshot(deps, options = {}) {
|
|
146103
|
+
const { provider, appContext, workingDirectory } = deps;
|
|
146104
|
+
const commitLimit = options.commitLimit ?? 2;
|
|
146105
|
+
const tagLimit = options.tagLimit ?? 2;
|
|
146106
|
+
const tenantId = appContext.tenantId || "default-tenant";
|
|
146107
|
+
const context = {
|
|
146108
|
+
workingDirectory,
|
|
146109
|
+
requestContext: appContext,
|
|
146110
|
+
tenantId
|
|
146111
|
+
};
|
|
146112
|
+
const fetchStatus = provider.status({ includeUntracked: true }, context);
|
|
146113
|
+
const fetchLog = provider.log({ maxCount: commitLimit }, context);
|
|
146114
|
+
const fetchTags = provider.tag({ mode: "list", limit: tagLimit }, context);
|
|
146115
|
+
const fetchRemotes = options.includeRemotes ? provider.remote({ mode: "list" }, context) : Promise.resolve(undefined);
|
|
146116
|
+
const [statusRes, logRes, tagsRes, remotesRes] = await Promise.allSettled([
|
|
146117
|
+
fetchStatus,
|
|
146118
|
+
fetchLog,
|
|
146119
|
+
fetchTags,
|
|
146120
|
+
fetchRemotes
|
|
146121
|
+
]);
|
|
146122
|
+
const settled = [statusRes, logRes, tagsRes, remotesRes];
|
|
146123
|
+
const rejections = settled.filter((s2) => s2.status === "rejected");
|
|
146124
|
+
if (rejections.length > 0 && rejections.every((r2) => isNotARepoError(r2.reason))) {
|
|
146125
|
+
logger.debug("Repository snapshot skipped: path is not a git repository", {
|
|
146126
|
+
...appContext,
|
|
146127
|
+
workingDirectory
|
|
146128
|
+
});
|
|
146129
|
+
return { warnings: [NOT_A_REPO_HINT] };
|
|
146130
|
+
}
|
|
146131
|
+
const warnings = [];
|
|
146132
|
+
const status = statusRes.status === "fulfilled" ? {
|
|
146133
|
+
branch: statusRes.value.currentBranch,
|
|
146134
|
+
isClean: statusRes.value.isClean,
|
|
146135
|
+
staged: [
|
|
146136
|
+
...statusRes.value.stagedChanges.added ?? [],
|
|
146137
|
+
...statusRes.value.stagedChanges.modified ?? [],
|
|
146138
|
+
...statusRes.value.stagedChanges.deleted ?? [],
|
|
146139
|
+
...statusRes.value.stagedChanges.renamed ?? [],
|
|
146140
|
+
...statusRes.value.stagedChanges.copied ?? []
|
|
146141
|
+
],
|
|
146142
|
+
unstaged: [
|
|
146143
|
+
...statusRes.value.unstagedChanges.added ?? [],
|
|
146144
|
+
...statusRes.value.unstagedChanges.modified ?? [],
|
|
146145
|
+
...statusRes.value.unstagedChanges.deleted ?? []
|
|
146146
|
+
],
|
|
146147
|
+
untracked: statusRes.value.untrackedFiles,
|
|
146148
|
+
conflicts: statusRes.value.conflictedFiles,
|
|
146149
|
+
...statusRes.value.upstream ? { upstream: statusRes.value.upstream } : {},
|
|
146150
|
+
...typeof statusRes.value.ahead === "number" ? { ahead: statusRes.value.ahead } : {},
|
|
146151
|
+
...typeof statusRes.value.behind === "number" ? { behind: statusRes.value.behind } : {}
|
|
146152
|
+
} : {
|
|
146153
|
+
branch: null,
|
|
146154
|
+
isClean: false,
|
|
146155
|
+
staged: [],
|
|
146156
|
+
unstaged: [],
|
|
146157
|
+
untracked: [],
|
|
146158
|
+
conflicts: []
|
|
146159
|
+
};
|
|
146160
|
+
if (statusRes.status === "rejected") {
|
|
146161
|
+
warnings.push(`status unavailable: ${reasonMessage(statusRes.reason)}`);
|
|
146162
|
+
}
|
|
146163
|
+
const recentCommits = logRes.status === "fulfilled" ? logRes.value.commits.map((commit) => ({
|
|
146164
|
+
hash: commit.shortHash,
|
|
146165
|
+
author: commit.author ?? "",
|
|
146166
|
+
date: typeof commit.timestamp === "number" ? new Date(commit.timestamp * 1000).toISOString() : "",
|
|
146167
|
+
subject: commit.subject
|
|
146168
|
+
})) : [];
|
|
146169
|
+
if (logRes.status === "rejected" && !isEmptyRepoError(logRes.reason)) {
|
|
146170
|
+
warnings.push(`recent commits unavailable: ${reasonMessage(logRes.reason)}`);
|
|
146171
|
+
}
|
|
146172
|
+
const recentTags = tagsRes.status === "fulfilled" && tagsRes.value.mode === "list" ? (tagsRes.value.tags ?? []).map((tag) => {
|
|
146173
|
+
const entry = { name: tag.name };
|
|
146174
|
+
const date6 = toIsoDate(tag.timestamp);
|
|
146175
|
+
if (date6)
|
|
146176
|
+
entry.date = date6;
|
|
146177
|
+
if (tag.tagger)
|
|
146178
|
+
entry.tagger = tag.tagger;
|
|
146179
|
+
if (tag.message)
|
|
146180
|
+
entry.annotationSubject = tag.message;
|
|
146181
|
+
if (tag.annotationBody)
|
|
146182
|
+
entry.annotationBody = tag.annotationBody;
|
|
146183
|
+
return entry;
|
|
146184
|
+
}) : [];
|
|
146185
|
+
if (tagsRes.status === "rejected") {
|
|
146186
|
+
warnings.push(`recent tags unavailable: ${reasonMessage(tagsRes.reason)}`);
|
|
146187
|
+
}
|
|
146188
|
+
let remotes;
|
|
146189
|
+
if (options.includeRemotes) {
|
|
146190
|
+
if (remotesRes.status === "fulfilled" && remotesRes.value && remotesRes.value.mode === "list") {
|
|
146191
|
+
remotes = (remotesRes.value.remotes ?? []).map((r2) => ({
|
|
146192
|
+
name: r2.name,
|
|
146193
|
+
fetchUrl: r2.fetchUrl,
|
|
146194
|
+
pushUrl: r2.pushUrl
|
|
146195
|
+
}));
|
|
146196
|
+
} else if (remotesRes.status === "rejected") {
|
|
146197
|
+
warnings.push(`remotes unavailable: ${reasonMessage(remotesRes.reason)}`);
|
|
146198
|
+
remotes = [];
|
|
146199
|
+
} else {
|
|
146200
|
+
remotes = [];
|
|
146201
|
+
}
|
|
146202
|
+
}
|
|
146203
|
+
const snapshot = {
|
|
146204
|
+
status,
|
|
146205
|
+
recentCommits,
|
|
146206
|
+
recentTags,
|
|
146207
|
+
...remotes !== undefined ? { remotes } : {}
|
|
146208
|
+
};
|
|
146209
|
+
return { snapshot, warnings };
|
|
146210
|
+
}
|
|
146211
|
+
|
|
146212
|
+
// src/mcp-server/tools/definitions/git-set-working-dir.tool.ts
|
|
146303
146213
|
var TOOL_NAME8 = "git_set_working_dir";
|
|
146304
146214
|
var TOOL_TITLE8 = "Git Set Working Directory";
|
|
146305
|
-
var TOOL_DESCRIPTION8 = "Set the session working directory for all git operations
|
|
146215
|
+
var TOOL_DESCRIPTION8 = "Set the session working directory for all git operations so subsequent calls can omit the path parameter. Always returns a repository snapshot (status, recent commits, recent tags, remotes) to orient the caller.";
|
|
146306
146216
|
var InputSchema8 = exports_external.object({
|
|
146307
146217
|
path: exports_external.string().min(1).describe("Absolute path to the git repository to use as the working directory."),
|
|
146308
146218
|
validateGitRepo: exports_external.boolean().default(true).describe("Validate that the path is a Git repository."),
|
|
146309
|
-
initializeIfNotPresent: exports_external.boolean().default(false).describe("If not a Git repository, initialize it with 'git init'.")
|
|
146310
|
-
includeMetadata: exports_external.boolean().default(false).describe("Include repository metadata (status, branches, remotes, recent commits) in the response. Set to true for immediate repository context understanding. Defaults to false to minimize response size.")
|
|
146219
|
+
initializeIfNotPresent: exports_external.boolean().default(false).describe("If not a Git repository, initialize it with 'git init'.")
|
|
146311
146220
|
});
|
|
146312
146221
|
var OutputSchema9 = exports_external.object({
|
|
146313
146222
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
|
146314
146223
|
path: exports_external.string().describe("The working directory that was set."),
|
|
146315
146224
|
message: exports_external.string().describe("Confirmation message."),
|
|
146316
|
-
|
|
146317
|
-
status:
|
|
146318
|
-
|
|
146319
|
-
|
|
146320
|
-
|
|
146321
|
-
|
|
146322
|
-
|
|
146323
|
-
|
|
146324
|
-
|
|
146325
|
-
|
|
146326
|
-
|
|
146327
|
-
totalLocal: exports_external.number().int().describe("Total number of local branches."),
|
|
146328
|
-
totalRemote: exports_external.number().int().describe("Total number of remote-tracking branches."),
|
|
146329
|
-
upstream: exports_external.string().optional().describe("Upstream branch name if current branch is tracking one."),
|
|
146330
|
-
ahead: exports_external.number().int().optional().describe("Commits ahead of upstream (if tracking)."),
|
|
146331
|
-
behind: exports_external.number().int().optional().describe("Commits behind upstream (if tracking).")
|
|
146332
|
-
}).describe("Branch information and tracking status."),
|
|
146333
|
-
remotes: exports_external.array(exports_external.object({
|
|
146334
|
-
name: exports_external.string().describe("Remote name."),
|
|
146335
|
-
fetchUrl: exports_external.string().describe("Fetch URL."),
|
|
146336
|
-
pushUrl: exports_external.string().describe("Push URL (may differ from fetch).")
|
|
146337
|
-
})).describe("Configured remote repositories."),
|
|
146338
|
-
recentCommits: exports_external.array(exports_external.object({
|
|
146339
|
-
hash: exports_external.string().describe("Commit hash (short form)."),
|
|
146340
|
-
author: exports_external.string().describe("Commit author name."),
|
|
146341
|
-
date: exports_external.string().describe("Commit date (ISO 8601 format)."),
|
|
146342
|
-
message: exports_external.string().describe("Commit message (first line).")
|
|
146343
|
-
})).describe("Recent commits (up to 5 most recent).")
|
|
146344
|
-
}).optional().describe("Rich repository metadata including status, branches, remotes, and recent history. Only included when includeMetadata parameter is true.")
|
|
146345
|
-
});
|
|
146346
|
-
async function gatherRepositoryContext(targetPath, dependencies) {
|
|
146225
|
+
repository: exports_external.object({
|
|
146226
|
+
status: RepoSnapshotStatusSchema,
|
|
146227
|
+
recentCommits: exports_external.array(RepoSnapshotCommitSchema).describe("Up to 2 most recent commits on the current branch."),
|
|
146228
|
+
recentTags: exports_external.array(RepoSnapshotTagSchema).describe("Up to 2 most recent tags by creator date."),
|
|
146229
|
+
remotes: exports_external.array(RepoSnapshotRemoteSchema).describe("Configured remote repositories.")
|
|
146230
|
+
}).optional().describe("Best-effort repository snapshot. Omitted when the path is not a git repository (see enrichmentWarnings)."),
|
|
146231
|
+
enrichmentWarnings: exports_external.array(exports_external.string()).optional().describe("Actionable notes when snapshot gathering was skipped or partially failed.")
|
|
146232
|
+
});
|
|
146233
|
+
async function ensureRepositoryReady(input, dependencies, tenantId) {
|
|
146234
|
+
if (!input.validateGitRepo)
|
|
146235
|
+
return;
|
|
146347
146236
|
const { provider, appContext } = dependencies;
|
|
146348
|
-
const
|
|
146349
|
-
|
|
146350
|
-
workingDirectory: targetPath,
|
|
146237
|
+
const opContext = {
|
|
146238
|
+
workingDirectory: input.path,
|
|
146351
146239
|
requestContext: appContext,
|
|
146352
146240
|
tenantId
|
|
146353
146241
|
};
|
|
146354
146242
|
try {
|
|
146355
|
-
|
|
146356
|
-
statusResult,
|
|
146357
|
-
localBranchesResult,
|
|
146358
|
-
remoteBranchesResult,
|
|
146359
|
-
remotesResult,
|
|
146360
|
-
logResult
|
|
146361
|
-
] = await Promise.allSettled([
|
|
146362
|
-
provider.status({ includeUntracked: true }, context),
|
|
146363
|
-
provider.branch({ mode: "list" }, context),
|
|
146364
|
-
provider.branch({ mode: "list", remote: true }, context),
|
|
146365
|
-
provider.remote({ mode: "list" }, context),
|
|
146366
|
-
provider.log({ maxCount: 5 }, context)
|
|
146367
|
-
]);
|
|
146368
|
-
const status = statusResult.status === "fulfilled" ? {
|
|
146369
|
-
branch: statusResult.value.currentBranch,
|
|
146370
|
-
isClean: statusResult.value.isClean,
|
|
146371
|
-
stagedCount: (statusResult.value.stagedChanges.added?.length || 0) + (statusResult.value.stagedChanges.modified?.length || 0) + (statusResult.value.stagedChanges.deleted?.length || 0) + (statusResult.value.stagedChanges.renamed?.length || 0) + (statusResult.value.stagedChanges.copied?.length || 0),
|
|
146372
|
-
unstagedCount: (statusResult.value.unstagedChanges.added?.length || 0) + (statusResult.value.unstagedChanges.modified?.length || 0) + (statusResult.value.unstagedChanges.deleted?.length || 0),
|
|
146373
|
-
untrackedCount: statusResult.value.untrackedFiles.length,
|
|
146374
|
-
conflictsCount: statusResult.value.conflictedFiles.length
|
|
146375
|
-
} : {
|
|
146376
|
-
branch: null,
|
|
146377
|
-
isClean: false,
|
|
146378
|
-
stagedCount: 0,
|
|
146379
|
-
unstagedCount: 0,
|
|
146380
|
-
untrackedCount: 0,
|
|
146381
|
-
conflictsCount: 0
|
|
146382
|
-
};
|
|
146383
|
-
const localBranches = localBranchesResult.status === "fulfilled" && localBranchesResult.value.mode === "list" ? localBranchesResult.value.branches : [];
|
|
146384
|
-
const remoteBranchCount = remoteBranchesResult.status === "fulfilled" && remoteBranchesResult.value.mode === "list" ? remoteBranchesResult.value.branches.length : 0;
|
|
146385
|
-
const currentBranch = localBranches.find((b) => b.current);
|
|
146386
|
-
const branches = {
|
|
146387
|
-
current: currentBranch?.name || null,
|
|
146388
|
-
totalLocal: localBranches.length,
|
|
146389
|
-
totalRemote: remoteBranchCount,
|
|
146390
|
-
upstream: currentBranch?.upstream,
|
|
146391
|
-
ahead: currentBranch?.ahead,
|
|
146392
|
-
behind: currentBranch?.behind
|
|
146393
|
-
};
|
|
146394
|
-
const remotes = remotesResult.status === "fulfilled" && remotesResult.value.mode === "list" ? remotesResult.value.remotes || [] : [];
|
|
146395
|
-
const recentCommits = logResult.status === "fulfilled" ? logResult.value.commits.map((commit) => ({
|
|
146396
|
-
hash: commit.shortHash,
|
|
146397
|
-
author: commit.author,
|
|
146398
|
-
date: new Date(commit.timestamp * 1000).toISOString(),
|
|
146399
|
-
message: commit.subject
|
|
146400
|
-
})) : [];
|
|
146401
|
-
return {
|
|
146402
|
-
status,
|
|
146403
|
-
branches,
|
|
146404
|
-
remotes,
|
|
146405
|
-
recentCommits
|
|
146406
|
-
};
|
|
146407
|
-
} catch (error48) {
|
|
146408
|
-
const { logger: logger3 } = await Promise.resolve().then(() => (init_utils(), exports_utils));
|
|
146409
|
-
logger3.debug("Failed to gather repository context", {
|
|
146410
|
-
...appContext,
|
|
146411
|
-
error: error48 instanceof Error ? error48.message : String(error48),
|
|
146412
|
-
targetPath
|
|
146413
|
-
});
|
|
146243
|
+
await provider.validateRepository(input.path, opContext);
|
|
146414
146244
|
return;
|
|
146245
|
+
} catch (error48) {
|
|
146246
|
+
if (input.initializeIfNotPresent) {
|
|
146247
|
+
await provider.init({ path: input.path, initialBranch: "main", bare: false }, opContext);
|
|
146248
|
+
return;
|
|
146249
|
+
}
|
|
146250
|
+
const original = error48 instanceof Error ? error48.message : String(error48);
|
|
146251
|
+
throw new McpError(-32007 /* ValidationError */, `Path is not a git repository: ${input.path}. Pass initializeIfNotPresent: true to run 'git init' here, or point at an existing repository. Underlying error: ${original}`, { path: input.path });
|
|
146415
146252
|
}
|
|
146416
146253
|
}
|
|
146417
146254
|
async function gitSetWorkingDirLogic(input, dependencies) {
|
|
146418
146255
|
const { provider, storage, appContext } = dependencies;
|
|
146419
146256
|
const tenantId = appContext.tenantId || "default-tenant";
|
|
146420
|
-
|
|
146421
|
-
try {
|
|
146422
|
-
await provider.validateRepository(input.path, {
|
|
146423
|
-
workingDirectory: input.path,
|
|
146424
|
-
requestContext: appContext,
|
|
146425
|
-
tenantId
|
|
146426
|
-
});
|
|
146427
|
-
} catch (error48) {
|
|
146428
|
-
if (input.initializeIfNotPresent) {
|
|
146429
|
-
await provider.init({
|
|
146430
|
-
path: input.path,
|
|
146431
|
-
initialBranch: "main",
|
|
146432
|
-
bare: false
|
|
146433
|
-
}, {
|
|
146434
|
-
workingDirectory: input.path,
|
|
146435
|
-
requestContext: appContext,
|
|
146436
|
-
tenantId
|
|
146437
|
-
});
|
|
146438
|
-
} else {
|
|
146439
|
-
throw error48;
|
|
146440
|
-
}
|
|
146441
|
-
}
|
|
146442
|
-
}
|
|
146257
|
+
await ensureRepositoryReady(input, dependencies, tenantId);
|
|
146443
146258
|
const storageKey = `session:workingDir:${tenantId}`;
|
|
146444
146259
|
await storage.set(storageKey, input.path, appContext);
|
|
146445
|
-
const
|
|
146260
|
+
const { snapshot, warnings } = await gatherRepoSnapshot({ provider, appContext, workingDirectory: input.path }, { commitLimit: 2, tagLimit: 2, includeRemotes: true });
|
|
146446
146261
|
return {
|
|
146447
146262
|
success: true,
|
|
146448
146263
|
path: input.path,
|
|
146449
146264
|
message: `Working directory set to: ${input.path}`,
|
|
146450
|
-
|
|
146265
|
+
...snapshot ? {
|
|
146266
|
+
repository: {
|
|
146267
|
+
status: snapshot.status,
|
|
146268
|
+
recentCommits: snapshot.recentCommits,
|
|
146269
|
+
recentTags: snapshot.recentTags,
|
|
146270
|
+
remotes: snapshot.remotes ?? []
|
|
146271
|
+
}
|
|
146272
|
+
} : {},
|
|
146273
|
+
...warnings.length > 0 ? { enrichmentWarnings: warnings } : {}
|
|
146451
146274
|
};
|
|
146452
146275
|
}
|
|
146453
146276
|
function filterGitSetWorkingDirOutput(result, level) {
|
|
146454
146277
|
if (level === "minimal") {
|
|
146455
|
-
return {
|
|
146456
|
-
success: result.success,
|
|
146457
|
-
path: result.path
|
|
146458
|
-
};
|
|
146278
|
+
return { success: result.success, path: result.path };
|
|
146459
146279
|
}
|
|
146460
146280
|
return result;
|
|
146461
146281
|
}
|
|
@@ -146485,6 +146305,9 @@ var InputSchema9 = exports_external.object({
|
|
|
146485
146305
|
var OutputSchema10 = exports_external.object({
|
|
146486
146306
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
|
146487
146307
|
currentBranch: exports_external.string().nullable().describe("Current branch name."),
|
|
146308
|
+
upstream: exports_external.string().optional().describe("Upstream ref the current branch is tracking (if any)."),
|
|
146309
|
+
ahead: exports_external.number().int().optional().describe("Commits ahead of upstream (if tracking)."),
|
|
146310
|
+
behind: exports_external.number().int().optional().describe("Commits behind upstream (if tracking)."),
|
|
146488
146311
|
isClean: exports_external.boolean().describe("True if working directory is clean (no staged, unstaged, or untracked changes). When includeUntracked is false, untracked files are excluded from this check."),
|
|
146489
146312
|
stagedChanges: exports_external.object({
|
|
146490
146313
|
added: exports_external.array(exports_external.string()).optional().describe("Files added to the index (staged)."),
|
|
@@ -146512,6 +146335,9 @@ async function gitStatusLogic(input, { provider, targetPath, appContext }) {
|
|
|
146512
146335
|
return {
|
|
146513
146336
|
success: true,
|
|
146514
146337
|
currentBranch: result.currentBranch,
|
|
146338
|
+
...result.upstream !== undefined && { upstream: result.upstream },
|
|
146339
|
+
...result.ahead !== undefined && { ahead: result.ahead },
|
|
146340
|
+
...result.behind !== undefined && { behind: result.behind },
|
|
146515
146341
|
isClean: result.isClean,
|
|
146516
146342
|
stagedChanges: result.stagedChanges,
|
|
146517
146343
|
unstagedChanges: result.unstagedChanges,
|
|
@@ -146545,26 +146371,24 @@ var gitStatusTool = {
|
|
|
146545
146371
|
|
|
146546
146372
|
// src/mcp-server/tools/definitions/git-wrapup-instructions.tool.ts
|
|
146547
146373
|
init_zod();
|
|
146548
|
-
init_utils();
|
|
146549
146374
|
import { readFileSync } from "fs";
|
|
146550
146375
|
import path4 from "path";
|
|
146551
146376
|
init_config();
|
|
146552
146377
|
var TOOL_NAME10 = "git_wrapup_instructions";
|
|
146553
146378
|
var TOOL_TITLE10 = "Git Wrap-up Instructions";
|
|
146554
|
-
var TOOL_DESCRIPTION10 = "Returns a Git wrap-up protocol: an acceptance-criteria checklist the agent must satisfy before the session is considered shipped. Uses the operator's custom instructions if configured, otherwise emits a generic goals-strict/mechanism-generic default.
|
|
146379
|
+
var TOOL_DESCRIPTION10 = "Returns a Git wrap-up protocol: an acceptance-criteria checklist the agent must satisfy before the session is considered shipped. Uses the operator's custom instructions if configured, otherwise emits a generic goals-strict/mechanism-generic default. Enriches the response with a repository snapshot (status, recent commits, recent tags) so the agent has immediate orientation for the commit and release steps.";
|
|
146555
146380
|
var InputSchema10 = exports_external.object({
|
|
146556
146381
|
acknowledgement: exports_external.enum(["Y", "y", "Yes", "yes"]).describe("Acknowledgement to initiate the wrap-up workflow."),
|
|
146557
146382
|
createTag: exports_external.boolean().optional().describe("Controls whether the tag criterion appears in the emitted protocol. Omit or set `true` to include the tag step. Set `false` to omit it entirely — e.g., when tagging is deferred to a separate release step.")
|
|
146558
146383
|
});
|
|
146559
146384
|
var OutputSchema11 = exports_external.object({
|
|
146560
|
-
instructions: exports_external.string().describe("The
|
|
146561
|
-
|
|
146562
|
-
|
|
146563
|
-
|
|
146564
|
-
|
|
146565
|
-
|
|
146566
|
-
|
|
146567
|
-
gitStatusError: exports_external.string().optional().describe("Any error message if getting git status failed.")
|
|
146385
|
+
instructions: exports_external.string().describe("The wrap-up protocol to satisfy before the session ships."),
|
|
146386
|
+
repository: exports_external.object({
|
|
146387
|
+
status: RepoSnapshotStatusSchema,
|
|
146388
|
+
recentCommits: exports_external.array(RepoSnapshotCommitSchema).describe("Up to 2 most recent commits on the current branch."),
|
|
146389
|
+
recentTags: exports_external.array(RepoSnapshotTagSchema).describe("Up to 2 most recent tags by creator date.")
|
|
146390
|
+
}).optional().describe("Best-effort repository snapshot. Omitted when no working directory is set or when the path is not a git repository."),
|
|
146391
|
+
enrichmentWarnings: exports_external.array(exports_external.string()).optional().describe("Actionable notes when snapshot gathering was skipped or partially failed.")
|
|
146568
146392
|
});
|
|
146569
146393
|
function buildDefaultInstructions(input) {
|
|
146570
146394
|
const tagCriterion = input.createTag === false ? "" : "\n- [ ] Annotated tag at the project's convention (typically `v<version>`) with a concise message summarizing the real changes — no filler. Flag if a tag already exists at this commit.";
|
|
@@ -146633,49 +146457,32 @@ var customInstructions = loadCustomInstructions(config2?.git?.wrapupInstructions
|
|
|
146633
146457
|
async function gitWrapupInstructionsLogic(input, { provider, storage, appContext }) {
|
|
146634
146458
|
const tenantId = appContext.tenantId || "default-tenant";
|
|
146635
146459
|
const finalInstructions = customInstructions ?? buildDefaultInstructions(input);
|
|
146636
|
-
|
|
146637
|
-
|
|
146638
|
-
|
|
146639
|
-
|
|
146640
|
-
|
|
146641
|
-
|
|
146642
|
-
|
|
146643
|
-
|
|
146644
|
-
|
|
146645
|
-
tenantId
|
|
146646
|
-
});
|
|
146647
|
-
gitStatus = {
|
|
146648
|
-
branch: result.currentBranch || "detached HEAD",
|
|
146649
|
-
staged: [
|
|
146650
|
-
...result.stagedChanges.added || [],
|
|
146651
|
-
...result.stagedChanges.modified || [],
|
|
146652
|
-
...result.stagedChanges.deleted || []
|
|
146653
|
-
],
|
|
146654
|
-
unstaged: [
|
|
146655
|
-
...result.unstagedChanges.modified || [],
|
|
146656
|
-
...result.unstagedChanges.deleted || []
|
|
146657
|
-
],
|
|
146658
|
-
untracked: result.untrackedFiles
|
|
146659
|
-
};
|
|
146660
|
-
} else {
|
|
146661
|
-
gitStatusError = "No working directory set for session, git status skipped.";
|
|
146662
|
-
}
|
|
146663
|
-
} catch (error48) {
|
|
146664
|
-
const errorMessage = error48 instanceof Error ? error48.message : "Unknown error";
|
|
146665
|
-
gitStatusError = `Failed to get git status: ${errorMessage}`;
|
|
146666
|
-
logger.warning(gitStatusError, { ...appContext, error: error48 });
|
|
146460
|
+
const storageKey = `session:workingDir:${tenantId}`;
|
|
146461
|
+
const workingDir = await storage.get(storageKey, appContext);
|
|
146462
|
+
if (!workingDir) {
|
|
146463
|
+
return {
|
|
146464
|
+
instructions: finalInstructions,
|
|
146465
|
+
enrichmentWarnings: [
|
|
146466
|
+
"No session working directory set. Call git_set_working_dir first to include a repository snapshot (status, recent commits, recent tags) in this response."
|
|
146467
|
+
]
|
|
146468
|
+
};
|
|
146667
146469
|
}
|
|
146470
|
+
const { snapshot, warnings } = await gatherRepoSnapshot({ provider, appContext, workingDirectory: workingDir }, { commitLimit: 2, tagLimit: 2 });
|
|
146668
146471
|
return {
|
|
146669
146472
|
instructions: finalInstructions,
|
|
146670
|
-
|
|
146671
|
-
|
|
146473
|
+
...snapshot ? {
|
|
146474
|
+
repository: {
|
|
146475
|
+
status: snapshot.status,
|
|
146476
|
+
recentCommits: snapshot.recentCommits,
|
|
146477
|
+
recentTags: snapshot.recentTags
|
|
146478
|
+
}
|
|
146479
|
+
} : {},
|
|
146480
|
+
...warnings.length > 0 ? { enrichmentWarnings: warnings } : {}
|
|
146672
146481
|
};
|
|
146673
146482
|
}
|
|
146674
146483
|
function filterGitWrapupInstructionsOutput(result, level) {
|
|
146675
146484
|
if (level === "minimal") {
|
|
146676
|
-
return {
|
|
146677
|
-
instructions: result.instructions
|
|
146678
|
-
};
|
|
146485
|
+
return { instructions: result.instructions };
|
|
146679
146486
|
}
|
|
146680
146487
|
return result;
|
|
146681
146488
|
}
|
|
@@ -146841,10 +146648,8 @@ var InputSchema12 = exports_external.object({
|
|
|
146841
146648
|
}).optional().describe("Override commit author (defaults to git config)."),
|
|
146842
146649
|
amend: exports_external.boolean().default(false).describe("Amend the previous commit instead of creating a new one. Use with caution."),
|
|
146843
146650
|
allowEmpty: exports_external.boolean().default(false).describe("Allow creating a commit with no changes."),
|
|
146844
|
-
sign: SignSchema,
|
|
146845
146651
|
noVerify: NoVerifySchema,
|
|
146846
|
-
filesToStage: exports_external.array(exports_external.string()).optional().describe("File paths to stage before committing (atomic stage+commit operation).")
|
|
146847
|
-
forceUnsignedOnFailure: exports_external.boolean().default(false).describe("If GPG/SSH signing fails, retry the commit without signing instead of failing.")
|
|
146652
|
+
filesToStage: exports_external.array(exports_external.string()).optional().describe("File paths to stage before committing (atomic stage+commit operation).")
|
|
146848
146653
|
});
|
|
146849
146654
|
var OutputSchema13 = exports_external.object({
|
|
146850
146655
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
|
@@ -146856,6 +146661,8 @@ var OutputSchema13 = exports_external.object({
|
|
|
146856
146661
|
committedFiles: exports_external.array(exports_external.string()).describe("List of files that were committed."),
|
|
146857
146662
|
insertions: exports_external.number().int().optional().describe("Number of line insertions."),
|
|
146858
146663
|
deletions: exports_external.number().int().optional().describe("Number of line deletions."),
|
|
146664
|
+
signed: exports_external.boolean().describe("Whether the commit was signed. False when GIT_SIGN_COMMITS=false or when signing was attempted and fell back to unsigned on failure."),
|
|
146665
|
+
signingWarning: exports_external.string().optional().describe("Populated only when signing was requested but failed, and the commit was created unsigned as a fallback."),
|
|
146859
146666
|
status: exports_external.object({
|
|
146860
146667
|
current_branch: exports_external.string().nullable().describe("Current branch name after commit."),
|
|
146861
146668
|
staged_changes: exports_external.record(exports_external.string(), exports_external.any()).describe("Remaining staged changes after commit."),
|
|
@@ -146877,15 +146684,11 @@ async function gitCommitLogic(input, { provider, targetPath, appContext }) {
|
|
|
146877
146684
|
message: input.message,
|
|
146878
146685
|
amend: input.amend,
|
|
146879
146686
|
allowEmpty: input.allowEmpty,
|
|
146880
|
-
noVerify: input.noVerify
|
|
146881
|
-
forceUnsignedOnFailure: input.forceUnsignedOnFailure
|
|
146687
|
+
noVerify: input.noVerify
|
|
146882
146688
|
};
|
|
146883
146689
|
if (input.author !== undefined) {
|
|
146884
146690
|
commitOptions.author = input.author;
|
|
146885
146691
|
}
|
|
146886
|
-
if (input.sign !== undefined) {
|
|
146887
|
-
commitOptions.sign = input.sign;
|
|
146888
|
-
}
|
|
146889
146692
|
const result = await provider.commit(commitOptions, {
|
|
146890
146693
|
workingDirectory: targetPath,
|
|
146891
146694
|
requestContext: appContext,
|
|
@@ -146896,7 +146699,7 @@ async function gitCommitLogic(input, { provider, targetPath, appContext }) {
|
|
|
146896
146699
|
requestContext: appContext,
|
|
146897
146700
|
tenantId: appContext.tenantId || "default-tenant"
|
|
146898
146701
|
});
|
|
146899
|
-
|
|
146702
|
+
const output = {
|
|
146900
146703
|
success: result.success,
|
|
146901
146704
|
commitHash: result.commitHash,
|
|
146902
146705
|
message: result.message,
|
|
@@ -146904,6 +146707,7 @@ async function gitCommitLogic(input, { provider, targetPath, appContext }) {
|
|
|
146904
146707
|
timestamp: result.timestamp,
|
|
146905
146708
|
filesChanged: result.filesChanged.length,
|
|
146906
146709
|
committedFiles: result.filesChanged,
|
|
146710
|
+
signed: result.signed,
|
|
146907
146711
|
status: {
|
|
146908
146712
|
current_branch: statusResult.currentBranch,
|
|
146909
146713
|
staged_changes: flattenChanges(statusResult.stagedChanges),
|
|
@@ -146913,6 +146717,10 @@ async function gitCommitLogic(input, { provider, targetPath, appContext }) {
|
|
|
146913
146717
|
is_clean: statusResult.isClean
|
|
146914
146718
|
}
|
|
146915
146719
|
};
|
|
146720
|
+
if (result.signingWarning) {
|
|
146721
|
+
output.signingWarning = result.signingWarning;
|
|
146722
|
+
}
|
|
146723
|
+
return output;
|
|
146916
146724
|
}
|
|
146917
146725
|
function filterGitCommitOutput(result, level) {
|
|
146918
146726
|
if (level === "minimal") {
|
|
@@ -146920,6 +146728,8 @@ function filterGitCommitOutput(result, level) {
|
|
|
146920
146728
|
success: result.success,
|
|
146921
146729
|
commitHash: result.commitHash,
|
|
146922
146730
|
message: result.message,
|
|
146731
|
+
signed: result.signed,
|
|
146732
|
+
...result.signingWarning && { signingWarning: result.signingWarning },
|
|
146923
146733
|
status: {
|
|
146924
146734
|
current_branch: result.status.current_branch,
|
|
146925
146735
|
is_clean: result.status.is_clean,
|
|
@@ -146941,6 +146751,8 @@ function filterGitCommitOutput(result, level) {
|
|
|
146941
146751
|
insertions: result.insertions,
|
|
146942
146752
|
deletions: result.deletions,
|
|
146943
146753
|
committedFiles: result.committedFiles,
|
|
146754
|
+
signed: result.signed,
|
|
146755
|
+
...result.signingWarning && { signingWarning: result.signingWarning },
|
|
146944
146756
|
status: {
|
|
146945
146757
|
current_branch: result.status.current_branch,
|
|
146946
146758
|
is_clean: result.status.is_clean,
|
|
@@ -147102,7 +146914,8 @@ var CommitSchema = exports_external.object({
|
|
|
147102
146914
|
var OutputSchema15 = exports_external.object({
|
|
147103
146915
|
success: exports_external.boolean().describe("Indicates if the operation was successful."),
|
|
147104
146916
|
commits: exports_external.array(CommitSchema).describe("Array of commit objects."),
|
|
147105
|
-
totalCount: exports_external.number().int().describe("Total number of commits returned (may be limited by maxCount).")
|
|
146917
|
+
totalCount: exports_external.number().int().describe("Total number of commits returned (may be limited by maxCount)."),
|
|
146918
|
+
note: exports_external.string().optional().describe("Set when filters returned zero commits. Echoes the criteria and suggests broadening so callers can self-correct without inspecting the request.")
|
|
147106
146919
|
});
|
|
147107
146920
|
async function gitLogLogic(input, { provider, targetPath, appContext }) {
|
|
147108
146921
|
const result = await provider.log({
|
|
@@ -147123,15 +146936,25 @@ async function gitLogLogic(input, { provider, targetPath, appContext }) {
|
|
|
147123
146936
|
requestContext: appContext,
|
|
147124
146937
|
tenantId: appContext.tenantId || "default-tenant"
|
|
147125
146938
|
});
|
|
147126
|
-
const
|
|
147127
|
-
|
|
147128
|
-
|
|
147129
|
-
|
|
147130
|
-
|
|
146939
|
+
const appliedFilters = [];
|
|
146940
|
+
if (input.author)
|
|
146941
|
+
appliedFilters.push(`author=${input.author}`);
|
|
146942
|
+
if (input.grep)
|
|
146943
|
+
appliedFilters.push(`grep=${input.grep}`);
|
|
146944
|
+
if (input.since)
|
|
146945
|
+
appliedFilters.push(`since=${input.since}`);
|
|
146946
|
+
if (input.until)
|
|
146947
|
+
appliedFilters.push(`until=${input.until}`);
|
|
146948
|
+
if (input.filePath)
|
|
146949
|
+
appliedFilters.push(`filePath=${input.filePath}`);
|
|
146950
|
+
if (input.branch)
|
|
146951
|
+
appliedFilters.push(`branch=${input.branch}`);
|
|
146952
|
+
const note = result.commits.length === 0 && appliedFilters.length > 0 ? `No commits matched the applied filters (${appliedFilters.join(", ")}). Try removing filters or broadening the date/author/path criteria.` : undefined;
|
|
147131
146953
|
return {
|
|
147132
146954
|
success: true,
|
|
147133
|
-
commits,
|
|
147134
|
-
totalCount: result.totalCount
|
|
146955
|
+
commits: result.commits,
|
|
146956
|
+
totalCount: result.totalCount,
|
|
146957
|
+
...note && { note }
|
|
147135
146958
|
};
|
|
147136
146959
|
}
|
|
147137
146960
|
function filterGitLogOutput(result, level) {
|
|
@@ -147250,7 +147073,8 @@ var InputSchema16 = exports_external.object({
|
|
|
147250
147073
|
all: AllSchema.describe("For list operation: show both local and remote branches."),
|
|
147251
147074
|
remote: exports_external.boolean().default(false).describe("For list operation: show only remote branches."),
|
|
147252
147075
|
merged: exports_external.preprocess((val) => val === "true" ? true : val === "false" ? false : val, exports_external.union([exports_external.boolean(), CommitRefSchema])).optional().describe("For list operation: show only branches merged into HEAD (true) or specified commit (string)."),
|
|
147253
|
-
noMerged: exports_external.preprocess((val) => val === "true" ? true : val === "false" ? false : val, exports_external.union([exports_external.boolean(), CommitRefSchema])).optional().describe("For list operation: show only branches not merged into HEAD (true) or specified commit (string).")
|
|
147076
|
+
noMerged: exports_external.preprocess((val) => val === "true" ? true : val === "false" ? false : val, exports_external.union([exports_external.boolean(), CommitRefSchema])).optional().describe("For list operation: show only branches not merged into HEAD (true) or specified commit (string)."),
|
|
147077
|
+
limit: LimitSchema.describe("For list operation: cap the number of branches returned (applied at the git command). Use on repos with many branches.")
|
|
147254
147078
|
});
|
|
147255
147079
|
var BranchInfoSchema = exports_external.object({
|
|
147256
147080
|
name: exports_external.string().describe("Branch name."),
|
|
@@ -147269,18 +147093,18 @@ var OutputSchema17 = exports_external.object({
|
|
|
147269
147093
|
});
|
|
147270
147094
|
async function gitBranchLogic(input, { provider, targetPath, appContext }) {
|
|
147271
147095
|
if (input.operation === "show-current") {
|
|
147272
|
-
const result2 = await provider.branch({ mode: "
|
|
147096
|
+
const result2 = await provider.branch({ mode: "show-current" }, {
|
|
147273
147097
|
workingDirectory: targetPath,
|
|
147274
147098
|
requestContext: appContext,
|
|
147275
147099
|
tenantId: appContext.tenantId || "default-tenant"
|
|
147276
147100
|
});
|
|
147277
|
-
const current = result2.mode === "
|
|
147101
|
+
const current = result2.mode === "show-current" ? result2.current : null;
|
|
147278
147102
|
return {
|
|
147279
147103
|
success: true,
|
|
147280
147104
|
operation: "show-current",
|
|
147281
147105
|
branches: undefined,
|
|
147282
|
-
currentBranch: current
|
|
147283
|
-
message: current ? `Current branch: ${current
|
|
147106
|
+
currentBranch: current ?? undefined,
|
|
147107
|
+
message: current ? `Current branch: ${current}` : "Not on any branch (detached HEAD)"
|
|
147284
147108
|
};
|
|
147285
147109
|
}
|
|
147286
147110
|
const { path: _path, operation, name, newName, ...rest } = input;
|
|
@@ -147310,6 +147134,9 @@ async function gitBranchLogic(input, { provider, targetPath, appContext }) {
|
|
|
147310
147134
|
if (rest.noMerged !== undefined) {
|
|
147311
147135
|
branchOptions.noMerged = rest.noMerged;
|
|
147312
147136
|
}
|
|
147137
|
+
if (rest.limit !== undefined) {
|
|
147138
|
+
branchOptions.limit = rest.limit;
|
|
147139
|
+
}
|
|
147313
147140
|
const result = await provider.branch(branchOptions, {
|
|
147314
147141
|
workingDirectory: targetPath,
|
|
147315
147142
|
requestContext: appContext,
|
|
@@ -147339,7 +147166,7 @@ async function gitBranchLogic(input, { provider, targetPath, appContext }) {
|
|
|
147339
147166
|
currentBranch: undefined,
|
|
147340
147167
|
message: `Branch '${result.deleted}' deleted successfully.`
|
|
147341
147168
|
};
|
|
147342
|
-
} else {
|
|
147169
|
+
} else if (result.mode === "rename") {
|
|
147343
147170
|
return {
|
|
147344
147171
|
success: true,
|
|
147345
147172
|
operation: "rename",
|
|
@@ -147348,6 +147175,7 @@ async function gitBranchLogic(input, { provider, targetPath, appContext }) {
|
|
|
147348
147175
|
message: `Branch '${result.renamed.from}' renamed to '${result.renamed.to}'.`
|
|
147349
147176
|
};
|
|
147350
147177
|
}
|
|
147178
|
+
throw new Error(`Unexpected branch result mode: ${result.mode}`);
|
|
147351
147179
|
}
|
|
147352
147180
|
function filterGitBranchOutput(result, level) {
|
|
147353
147181
|
if (level === "minimal") {
|
|
@@ -148105,7 +147933,8 @@ var InputSchema26 = exports_external.object({
|
|
|
148105
147933
|
message: exports_external.string().optional().describe("Stash message description (for push operation)."),
|
|
148106
147934
|
stashRef: exports_external.string().optional().describe("Stash reference like stash@{0} (for pop/apply/drop operations)."),
|
|
148107
147935
|
includeUntracked: exports_external.boolean().default(false).describe("Include untracked files in the stash (for push operation)."),
|
|
148108
|
-
keepIndex: exports_external.boolean().default(false).describe("Don't revert staged changes (for push operation).")
|
|
147936
|
+
keepIndex: exports_external.boolean().default(false).describe("Don't revert staged changes (for push operation)."),
|
|
147937
|
+
limit: LimitSchema.describe("For list mode: cap the number of stash entries returned (applied at the git command).")
|
|
148109
147938
|
});
|
|
148110
147939
|
var StashInfoSchema = exports_external.object({
|
|
148111
147940
|
ref: exports_external.string().describe("Stash reference (e.g., stash@{0})."),
|
|
@@ -148139,6 +147968,9 @@ async function gitStashLogic(input, { provider, targetPath, appContext }) {
|
|
|
148139
147968
|
if (input.keepIndex !== undefined) {
|
|
148140
147969
|
stashOptions.keepIndex = input.keepIndex;
|
|
148141
147970
|
}
|
|
147971
|
+
if (input.limit !== undefined) {
|
|
147972
|
+
stashOptions.limit = input.limit;
|
|
147973
|
+
}
|
|
148142
147974
|
const result = await provider.stash(stashOptions, {
|
|
148143
147975
|
workingDirectory: targetPath,
|
|
148144
147976
|
requestContext: appContext,
|
|
@@ -148189,9 +148021,7 @@ var InputSchema27 = exports_external.object({
|
|
|
148189
148021
|
tagName: TagNameSchema.optional().describe("Tag name for create/delete operations."),
|
|
148190
148022
|
commit: CommitRefSchema.optional().describe("Commit to tag (default: HEAD for create operation)."),
|
|
148191
148023
|
message: exports_external.string().optional().describe("Tag message. Providing a message always produces an annotated tag (git does not support messages on lightweight tags). For release tags, summarize notable changes."),
|
|
148192
|
-
annotated: exports_external.boolean().default(false).describe('Create an annotated tag with a default "Tag <name>" message. Only effective when
|
|
148193
|
-
sign: SignSchema,
|
|
148194
|
-
forceUnsignedOnFailure: exports_external.boolean().default(false).describe("If GPG/SSH signing fails, retry the tag creation without signing instead of failing."),
|
|
148024
|
+
annotated: exports_external.boolean().default(false).describe('Create an annotated tag with a default "Tag <name>" message. Only effective when no message is provided and signing is disabled — otherwise the tag is always annotated.'),
|
|
148195
148025
|
force: ForceSchema.describe("Overwrite an existing tag (create mode only; has no effect on list or delete).")
|
|
148196
148026
|
});
|
|
148197
148027
|
var TagInfoSchema = exports_external.object({
|
|
@@ -148206,7 +148036,9 @@ var OutputSchema28 = exports_external.object({
|
|
|
148206
148036
|
mode: exports_external.string().describe("Operation mode that was performed."),
|
|
148207
148037
|
tags: exports_external.array(TagInfoSchema).optional().describe("List of tags (for list mode)."),
|
|
148208
148038
|
created: exports_external.string().optional().describe("Created tag name (for create mode)."),
|
|
148209
|
-
deleted: exports_external.string().optional().describe("Deleted tag name (for delete mode).")
|
|
148039
|
+
deleted: exports_external.string().optional().describe("Deleted tag name (for delete mode)."),
|
|
148040
|
+
signed: exports_external.boolean().optional().describe("Whether the created tag was signed. Only populated for create mode. False when GIT_SIGN_COMMITS=false or when signing failed and fell back to unsigned."),
|
|
148041
|
+
signingWarning: exports_external.string().optional().describe("Populated only when signing was requested but failed, and the tag was created unsigned as a fallback.")
|
|
148210
148042
|
});
|
|
148211
148043
|
async function gitTagLogic(input, { provider, targetPath, appContext }) {
|
|
148212
148044
|
if ((input.mode === "create" || input.mode === "delete") && !input.tagName) {
|
|
@@ -148215,8 +148047,7 @@ async function gitTagLogic(input, { provider, targetPath, appContext }) {
|
|
|
148215
148047
|
const tagOptions = {
|
|
148216
148048
|
mode: input.mode,
|
|
148217
148049
|
annotated: input.annotated,
|
|
148218
|
-
force: input.force
|
|
148219
|
-
forceUnsignedOnFailure: input.forceUnsignedOnFailure
|
|
148050
|
+
force: input.force
|
|
148220
148051
|
};
|
|
148221
148052
|
if (input.tagName !== undefined) {
|
|
148222
148053
|
tagOptions.tagName = input.tagName;
|
|
@@ -148227,27 +148058,33 @@ async function gitTagLogic(input, { provider, targetPath, appContext }) {
|
|
|
148227
148058
|
if (input.message !== undefined) {
|
|
148228
148059
|
tagOptions.message = normalizeMessage(input.message);
|
|
148229
148060
|
}
|
|
148230
|
-
if (input.sign !== undefined) {
|
|
148231
|
-
tagOptions.sign = input.sign;
|
|
148232
|
-
}
|
|
148233
148061
|
const result = await provider.tag(tagOptions, {
|
|
148234
148062
|
workingDirectory: targetPath,
|
|
148235
148063
|
requestContext: appContext,
|
|
148236
148064
|
tenantId: appContext.tenantId || "default-tenant"
|
|
148237
148065
|
});
|
|
148238
|
-
|
|
148066
|
+
const output = {
|
|
148239
148067
|
success: true,
|
|
148240
148068
|
mode: result.mode,
|
|
148241
148069
|
tags: result.tags,
|
|
148242
148070
|
created: result.created,
|
|
148243
148071
|
deleted: result.deleted
|
|
148244
148072
|
};
|
|
148073
|
+
if (result.signed !== undefined) {
|
|
148074
|
+
output.signed = result.signed;
|
|
148075
|
+
}
|
|
148076
|
+
if (result.signingWarning) {
|
|
148077
|
+
output.signingWarning = result.signingWarning;
|
|
148078
|
+
}
|
|
148079
|
+
return output;
|
|
148245
148080
|
}
|
|
148246
148081
|
function filterGitTagOutput(result, level) {
|
|
148247
148082
|
if (level === "minimal") {
|
|
148248
148083
|
return {
|
|
148249
148084
|
success: result.success,
|
|
148250
|
-
mode: result.mode
|
|
148085
|
+
mode: result.mode,
|
|
148086
|
+
...result.signed !== undefined && { signed: result.signed },
|
|
148087
|
+
...result.signingWarning && { signingWarning: result.signingWarning }
|
|
148251
148088
|
};
|
|
148252
148089
|
}
|
|
148253
148090
|
return result;
|
|
@@ -148466,7 +148303,6 @@ var registerTools = (container4) => {
|
|
|
148466
148303
|
};
|
|
148467
148304
|
|
|
148468
148305
|
// src/mcp-server/server.ts
|
|
148469
|
-
init_utils();
|
|
148470
148306
|
async function createMcpServerInstance() {
|
|
148471
148307
|
const context = requestContextService.createRequestContext({
|
|
148472
148308
|
operation: "createMcpServerInstance"
|
|
@@ -148510,7 +148346,6 @@ async function createMcpServerInstance() {
|
|
|
148510
148346
|
|
|
148511
148347
|
// src/mcp-server/transports/manager.ts
|
|
148512
148348
|
init_tokens();
|
|
148513
|
-
init_utils();
|
|
148514
148349
|
var import_tsyringe14 = __toESM(require_cjs2(), 1);
|
|
148515
148350
|
|
|
148516
148351
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
@@ -151018,11 +150853,11 @@ var MemoryEventStore = class {
|
|
|
151018
150853
|
#eventIdToStreamIdMap;
|
|
151019
150854
|
#idGenerator;
|
|
151020
150855
|
constructor(options = {}) {
|
|
151021
|
-
const { streamBufferSize = 100, eventsPerStreamBufferSize = 100, idGenerator:
|
|
150856
|
+
const { streamBufferSize = 100, eventsPerStreamBufferSize = 100, idGenerator: idGenerator2 = () => crypto.randomUUID() } = options;
|
|
151022
150857
|
this.#idToIndexMap = /* @__PURE__ */ new Map;
|
|
151023
150858
|
this.#eventIdToStreamIdMap = /* @__PURE__ */ new Map;
|
|
151024
150859
|
this.#eventsPerStreamBufferSize = eventsPerStreamBufferSize;
|
|
151025
|
-
this.#idGenerator =
|
|
150860
|
+
this.#idGenerator = idGenerator2;
|
|
151026
150861
|
this.#items = new RingBuffer(streamBufferSize, ({ streamId, events }) => {
|
|
151027
150862
|
this.#idToIndexMap.delete(streamId);
|
|
151028
150863
|
events.reset();
|
|
@@ -152266,13 +152101,8 @@ var serve = (options, listeningListener) => {
|
|
|
152266
152101
|
init_config();
|
|
152267
152102
|
import http3 from "http";
|
|
152268
152103
|
import { randomUUID } from "node:crypto";
|
|
152269
|
-
|
|
152270
|
-
// src/mcp-server/transports/auth/index.ts
|
|
152271
|
-
init_authContext();
|
|
152272
|
-
|
|
152273
152104
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
152274
152105
|
init_config();
|
|
152275
|
-
init_utils();
|
|
152276
152106
|
var import_tsyringe13 = __toESM(require_cjs2(), 1);
|
|
152277
152107
|
|
|
152278
152108
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
@@ -153760,7 +153590,6 @@ function createRemoteJWKSet(url2, options) {
|
|
|
153760
153590
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
153761
153591
|
init_tokens();
|
|
153762
153592
|
init_errors3();
|
|
153763
|
-
init_utils();
|
|
153764
153593
|
var import_tsyringe11 = __toESM(require_cjs2(), 1);
|
|
153765
153594
|
class JwtStrategy {
|
|
153766
153595
|
config;
|
|
@@ -153769,9 +153598,9 @@ class JwtStrategy {
|
|
|
153769
153598
|
env;
|
|
153770
153599
|
devMcpClientId;
|
|
153771
153600
|
devMcpScopes;
|
|
153772
|
-
constructor(config3,
|
|
153601
|
+
constructor(config3, logger2) {
|
|
153773
153602
|
this.config = config3;
|
|
153774
|
-
this.logger =
|
|
153603
|
+
this.logger = logger2;
|
|
153775
153604
|
const context = requestContextService.createRequestContext({
|
|
153776
153605
|
operation: "JwtStrategy.constructor"
|
|
153777
153606
|
});
|
|
@@ -153876,15 +153705,14 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
153876
153705
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
153877
153706
|
init_tokens();
|
|
153878
153707
|
init_errors3();
|
|
153879
|
-
init_utils();
|
|
153880
153708
|
var import_tsyringe12 = __toESM(require_cjs2(), 1);
|
|
153881
153709
|
class OauthStrategy {
|
|
153882
153710
|
config;
|
|
153883
153711
|
logger;
|
|
153884
153712
|
jwks;
|
|
153885
|
-
constructor(config3,
|
|
153713
|
+
constructor(config3, logger2) {
|
|
153886
153714
|
this.config = config3;
|
|
153887
|
-
this.logger =
|
|
153715
|
+
this.logger = logger2;
|
|
153888
153716
|
const context = requestContextService.createRequestContext({
|
|
153889
153717
|
operation: "OauthStrategy.constructor"
|
|
153890
153718
|
});
|
|
@@ -154029,8 +153857,6 @@ function createAuthStrategy() {
|
|
|
154029
153857
|
}
|
|
154030
153858
|
// src/mcp-server/transports/auth/authMiddleware.ts
|
|
154031
153859
|
init_errors3();
|
|
154032
|
-
init_utils();
|
|
154033
|
-
init_authContext();
|
|
154034
153860
|
function createAuthMiddleware(strategy) {
|
|
154035
153861
|
return async function authMiddleware(c, next) {
|
|
154036
153862
|
const context = requestContextService.createRequestContext({
|
|
@@ -154079,7 +153905,6 @@ function createAuthMiddleware(strategy) {
|
|
|
154079
153905
|
}
|
|
154080
153906
|
// src/mcp-server/transports/http/httpErrorHandler.ts
|
|
154081
153907
|
init_errors3();
|
|
154082
|
-
init_utils();
|
|
154083
153908
|
var httpErrorHandler = async (err, c) => {
|
|
154084
153909
|
const context = requestContextService.createRequestContext({
|
|
154085
153910
|
operation: "httpErrorHandler",
|
|
@@ -154164,8 +153989,6 @@ var httpErrorHandler = async (err, c) => {
|
|
|
154164
153989
|
};
|
|
154165
153990
|
|
|
154166
153991
|
// src/mcp-server/transports/http/sessionManager.ts
|
|
154167
|
-
init_utils();
|
|
154168
|
-
|
|
154169
153992
|
class SessionManager {
|
|
154170
153993
|
static instance = null;
|
|
154171
153994
|
sessions = new Map;
|
|
@@ -154324,7 +154147,6 @@ class SessionManager {
|
|
|
154324
154147
|
}
|
|
154325
154148
|
|
|
154326
154149
|
// src/mcp-server/transports/http/httpTransport.ts
|
|
154327
|
-
init_utils();
|
|
154328
154150
|
function createHttpApp(createMcpServer, parentContext) {
|
|
154329
154151
|
const app = new Hono2;
|
|
154330
154152
|
const transportContext = {
|
|
@@ -154700,7 +154522,6 @@ class StdioServerTransport {
|
|
|
154700
154522
|
}
|
|
154701
154523
|
|
|
154702
154524
|
// src/mcp-server/transports/stdio/stdioTransport.ts
|
|
154703
|
-
init_utils();
|
|
154704
154525
|
async function startStdioTransport(server, parentContext) {
|
|
154705
154526
|
const operationContext = {
|
|
154706
154527
|
...parentContext,
|
|
@@ -154747,9 +154568,9 @@ class TransportManager {
|
|
|
154747
154568
|
logger;
|
|
154748
154569
|
createMcpServer;
|
|
154749
154570
|
serverInstance = null;
|
|
154750
|
-
constructor(config3,
|
|
154571
|
+
constructor(config3, logger2, createMcpServer) {
|
|
154751
154572
|
this.config = config3;
|
|
154752
|
-
this.logger =
|
|
154573
|
+
this.logger = logger2;
|
|
154753
154574
|
this.createMcpServer = createMcpServer;
|
|
154754
154575
|
}
|
|
154755
154576
|
async start() {
|
|
@@ -154802,7 +154623,6 @@ TransportManager = __legacyDecorateClassTS([
|
|
|
154802
154623
|
], TransportManager);
|
|
154803
154624
|
|
|
154804
154625
|
// src/container/registrations/mcp.ts
|
|
154805
|
-
init_utils();
|
|
154806
154626
|
var registerMcpServices = () => {
|
|
154807
154627
|
import_tsyringe15.container.registerSingleton(ToolRegistry);
|
|
154808
154628
|
import_tsyringe15.container.registerSingleton(ResourceRegistry);
|
|
@@ -154898,11 +154718,11 @@ var start = async () => {
|
|
|
154898
154718
|
}
|
|
154899
154719
|
await logger.initialize(validatedMcpLogLevel, config3.mcpTransportType);
|
|
154900
154720
|
logger.info(`Logger initialized. Effective MCP logging level: ${validatedMcpLogLevel}.`, requestContextService.createRequestContext({ operation: "LoggerInit" }));
|
|
154901
|
-
const
|
|
154721
|
+
const runtime = detectRuntime();
|
|
154902
154722
|
const runtimeDesc = getRuntimeDescription();
|
|
154903
154723
|
logger.info(`Runtime detected: ${runtimeDesc}`, requestContextService.createRequestContext({
|
|
154904
154724
|
operation: "RuntimeDetection",
|
|
154905
|
-
runtime
|
|
154725
|
+
runtime,
|
|
154906
154726
|
runtimeVersion: runtimeDesc
|
|
154907
154727
|
}));
|
|
154908
154728
|
logger.info(`Storage service initialized with provider: ${config3.storage.providerType}`, requestContextService.createRequestContext({ operation: "StorageInit" }));
|