@devshub198211/devguard 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ai.cjs DELETED
@@ -1,867 +0,0 @@
1
- 'use strict';
2
-
3
- var fs = require('fs');
4
- var path = require('path');
5
- var crypto = require('crypto');
6
-
7
- function _interopNamespace(e) {
8
- if (e && e.__esModule) return e;
9
- var n = Object.create(null);
10
- if (e) {
11
- Object.keys(e).forEach(function (k) {
12
- if (k !== 'default') {
13
- var d = Object.getOwnPropertyDescriptor(e, k);
14
- Object.defineProperty(n, k, d.get ? d : {
15
- enumerable: true,
16
- get: function () { return e[k]; }
17
- });
18
- }
19
- });
20
- }
21
- n.default = e;
22
- return Object.freeze(n);
23
- }
24
-
25
- var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
26
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
27
- var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
28
-
29
- // src/dx/api-contract.ts
30
- var Schema = class {
31
- constructor() {
32
- /** @internal */
33
- this._isOptional = false;
34
- }
35
- safeParse(val) {
36
- try {
37
- let result = this._parse(val === void 0 ? this._default : val, "");
38
- if (this._transform) result = this._transform(result);
39
- return { success: true, data: result, errors: [] };
40
- } catch (e) {
41
- return { success: false, errors: parseErrors(e) };
42
- }
43
- }
44
- parse(val) {
45
- const r = this.safeParse(val);
46
- if (!r.success) throw new Error(r.errors.map((e) => (e.path ? `${e.path}: ` : "") + e.message).join("; "));
47
- return r.data;
48
- }
49
- optional() {
50
- return new OptionalSchema(this);
51
- }
52
- nullable() {
53
- return new NullableSchema(this);
54
- }
55
- default(val) {
56
- const c2 = Object.create(this);
57
- c2._default = val;
58
- return c2;
59
- }
60
- describe(desc) {
61
- const c2 = Object.create(this);
62
- c2._description = desc;
63
- return c2;
64
- }
65
- transform(fn) {
66
- const c2 = Object.create(this);
67
- c2._transform = fn;
68
- return c2;
69
- }
70
- toJSONSchema() {
71
- return {};
72
- }
73
- };
74
- function parseErrors(e) {
75
- if (e instanceof ValidationException) return e.errors;
76
- return [{ path: "", message: e?.message ?? "Unknown error" }];
77
- }
78
- var ValidationException = class extends Error {
79
- constructor(errors) {
80
- super(errors.map((e) => e.message).join("; "));
81
- this.errors = errors;
82
- }
83
- };
84
- function fail(path2, message) {
85
- throw new ValidationException([{ path: path2, message }]);
86
- }
87
- var OptionalSchema = class extends Schema {
88
- constructor(inner) {
89
- super();
90
- this.inner = inner;
91
- }
92
- _parse(val, path2) {
93
- if (val === void 0 || val === null) return void 0;
94
- return this.inner._parse(val, path2);
95
- }
96
- };
97
- var NullableSchema = class extends Schema {
98
- constructor(inner) {
99
- super();
100
- this.inner = inner;
101
- }
102
- _parse(val, path2) {
103
- if (val === null || val === void 0) return null;
104
- return this.inner._parse(val, path2);
105
- }
106
- };
107
- var StringSchema = class extends Schema {
108
- constructor() {
109
- super(...arguments);
110
- this._email = false;
111
- this._url = false;
112
- this._trim = false;
113
- }
114
- _parse(val, path2) {
115
- if (typeof val !== "string") fail(path2, `Expected string, got ${typeof val}`);
116
- let s = val;
117
- if (this._trim) s = s.trim();
118
- if (this._min !== void 0 && s.length < this._min) fail(path2, `Too short (min ${this._min})`);
119
- if (this._max !== void 0 && s.length > this._max) fail(path2, `Too long (max ${this._max})`);
120
- if (this._enum && !this._enum.includes(s)) fail(path2, `Must be one of: ${this._enum.join(", ")}`);
121
- if (this._regex && !this._regex.test(s)) fail(path2, `Does not match ${this._regex}`);
122
- if (this._email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)) fail(path2, "Invalid email address");
123
- if (this._url) {
124
- try {
125
- new URL(s);
126
- } catch {
127
- fail(path2, "Invalid URL");
128
- }
129
- }
130
- return s;
131
- }
132
- min(n) {
133
- const c2 = Object.create(this);
134
- c2._min = n;
135
- return c2;
136
- }
137
- max(n) {
138
- const c2 = Object.create(this);
139
- c2._max = n;
140
- return c2;
141
- }
142
- length(n) {
143
- return this.min(n).max(n);
144
- }
145
- enum(vals) {
146
- const c2 = Object.create(this);
147
- c2._enum = vals;
148
- return c2;
149
- }
150
- regex(r) {
151
- const c2 = Object.create(this);
152
- c2._regex = r;
153
- return c2;
154
- }
155
- email() {
156
- const c2 = Object.create(this);
157
- c2._email = true;
158
- return c2;
159
- }
160
- url() {
161
- const c2 = Object.create(this);
162
- c2._url = true;
163
- return c2;
164
- }
165
- trim() {
166
- const c2 = Object.create(this);
167
- c2._trim = true;
168
- return c2;
169
- }
170
- toJSONSchema() {
171
- return { type: "string", ...this._min ? { minLength: this._min } : {}, ...this._max ? { maxLength: this._max } : {}, ...this._enum ? { enum: this._enum } : {}, ...this._email ? { format: "email" } : {}, ...this._url ? { format: "uri" } : {} };
172
- }
173
- };
174
- var NumberSchema = class extends Schema {
175
- constructor() {
176
- super(...arguments);
177
- this._int = false;
178
- this._positive = false;
179
- }
180
- _parse(val, path2) {
181
- const n = typeof val === "string" ? parseFloat(val) : val;
182
- if (typeof n !== "number" || isNaN(n)) fail(path2, `Expected number, got ${typeof val}`);
183
- if (this._int && !Number.isInteger(n)) fail(path2, "Expected integer");
184
- if (this._positive && n <= 0) fail(path2, "Must be positive");
185
- if (this._min !== void 0 && n < this._min) fail(path2, `Too small (min ${this._min})`);
186
- if (this._max !== void 0 && n > this._max) fail(path2, `Too large (max ${this._max})`);
187
- return n;
188
- }
189
- min(n) {
190
- const c2 = Object.create(this);
191
- c2._min = n;
192
- return c2;
193
- }
194
- max(n) {
195
- const c2 = Object.create(this);
196
- c2._max = n;
197
- return c2;
198
- }
199
- int() {
200
- const c2 = Object.create(this);
201
- c2._int = true;
202
- return c2;
203
- }
204
- positive() {
205
- const c2 = Object.create(this);
206
- c2._positive = true;
207
- return c2;
208
- }
209
- toJSONSchema() {
210
- return { type: this._int ? "integer" : "number", ...this._min !== void 0 ? { minimum: this._min } : {}, ...this._max !== void 0 ? { maximum: this._max } : {} };
211
- }
212
- };
213
- var BooleanSchema = class extends Schema {
214
- _parse(val, path2) {
215
- if (val === "true" || val === 1 || val === "1") return true;
216
- if (val === "false" || val === 0 || val === "0") return false;
217
- if (typeof val !== "boolean") fail(path2, `Expected boolean, got ${typeof val}`);
218
- return val;
219
- }
220
- toJSONSchema() {
221
- return { type: "boolean" };
222
- }
223
- };
224
- var ObjectSchema = class _ObjectSchema extends Schema {
225
- constructor(shape, isStrict = false) {
226
- super();
227
- this.shape = shape;
228
- this._isStrict = isStrict;
229
- }
230
- _parse(val, path2) {
231
- if (typeof val !== "object" || val === null || Array.isArray(val)) fail(path2, `Expected object`);
232
- const obj = val;
233
- const result = {};
234
- const errors = [];
235
- for (const [key, schema] of Object.entries(this.shape)) {
236
- try {
237
- result[key] = schema._parse(obj[key], path2 ? `${path2}.${key}` : key);
238
- } catch (e) {
239
- errors.push(...parseErrors(e));
240
- }
241
- }
242
- if (this._isStrict) {
243
- const knownKeys = new Set(Object.keys(this.shape));
244
- for (const k of Object.keys(obj)) if (!knownKeys.has(k)) errors.push({ path: path2 ? `${path2}.${k}` : k, message: "Unknown field" });
245
- }
246
- if (errors.length) throw new ValidationException(errors);
247
- return result;
248
- }
249
- extend(extra) {
250
- return new _ObjectSchema({ ...this.shape, ...extra });
251
- }
252
- pick(keys) {
253
- const s = {};
254
- keys.forEach((k) => s[k] = this.shape[k]);
255
- return new _ObjectSchema(s);
256
- }
257
- omit(keys) {
258
- const s = { ...this.shape };
259
- keys.forEach((k) => delete s[k]);
260
- return new _ObjectSchema(s);
261
- }
262
- strict() {
263
- return new _ObjectSchema(this.shape, true);
264
- }
265
- toJSONSchema() {
266
- const props = {};
267
- const required = [];
268
- for (const [k, v] of Object.entries(this.shape)) {
269
- props[k] = v.toJSONSchema?.() ?? {};
270
- if (!(v instanceof OptionalSchema) && !(v instanceof NullableSchema)) required.push(k);
271
- }
272
- return { type: "object", properties: props, ...required.length ? { required } : {} };
273
- }
274
- };
275
- var ArraySchema = class extends Schema {
276
- constructor(item) {
277
- super();
278
- this.item = item;
279
- }
280
- _parse(val, path2) {
281
- if (!Array.isArray(val)) fail(path2, `Expected array`);
282
- if (this._min !== void 0 && val.length < this._min) fail(path2, `Too few items (min ${this._min})`);
283
- if (this._max !== void 0 && val.length > this._max) fail(path2, `Too many items (max ${this._max})`);
284
- const errors = [];
285
- const result = [];
286
- val.forEach((item, i) => {
287
- try {
288
- result.push(this.item._parse(item, `${path2}[${i}]`));
289
- } catch (e) {
290
- errors.push(...parseErrors(e));
291
- }
292
- });
293
- if (errors.length) throw new ValidationException(errors);
294
- return result;
295
- }
296
- min(n) {
297
- const c2 = Object.create(this);
298
- c2._min = n;
299
- return c2;
300
- }
301
- max(n) {
302
- const c2 = Object.create(this);
303
- c2._max = n;
304
- return c2;
305
- }
306
- nonempty() {
307
- return this.min(1);
308
- }
309
- toJSONSchema() {
310
- return { type: "array", items: this.item.toJSONSchema?.() ?? {} };
311
- }
312
- };
313
- var RecordSchema = class extends Schema {
314
- constructor(valueSchema) {
315
- super();
316
- this.valueSchema = valueSchema;
317
- }
318
- _parse(val, path2) {
319
- if (typeof val !== "object" || val === null || Array.isArray(val)) fail(path2, "Expected object");
320
- const result = {};
321
- for (const [k, v] of Object.entries(val)) {
322
- if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
323
- result[k] = this.valueSchema._parse(v, `${path2}.${k}`);
324
- }
325
- return result;
326
- }
327
- };
328
- var LiteralSchema = class extends Schema {
329
- constructor(literal) {
330
- super();
331
- this.literal = literal;
332
- }
333
- _parse(val, path2) {
334
- if (val !== this.literal) fail(path2, `Expected ${JSON.stringify(this.literal)}, got ${JSON.stringify(val)}`);
335
- return val;
336
- }
337
- };
338
- var UnionSchema = class extends Schema {
339
- constructor(options) {
340
- super();
341
- this.options = options;
342
- }
343
- _parse(val, path2) {
344
- for (const opt of this.options) {
345
- try {
346
- return opt._parse(val, path2);
347
- } catch {
348
- continue;
349
- }
350
- }
351
- fail(path2, `Value does not match any union variant`);
352
- }
353
- };
354
- var c = {
355
- string: () => new StringSchema(),
356
- number: () => new NumberSchema(),
357
- boolean: () => new BooleanSchema(),
358
- object: (shape) => new ObjectSchema(shape),
359
- array: (item) => new ArraySchema(item),
360
- record: (val) => new RecordSchema(val),
361
- literal: (v) => new LiteralSchema(v),
362
- union: (opts) => new UnionSchema(opts),
363
- any: () => new class extends Schema {
364
- _parse(v) {
365
- return v;
366
- }
367
- }()
368
- };
369
-
370
- // src/ai/agent-schema.ts
371
- function cleanLLMOutput(raw) {
372
- let s = raw.trim();
373
- s = s.replace(/^```(?:json|JSON)?\s*/m, "").replace(/```\s*$/m, "").trim();
374
- const openBrace = s.indexOf("{");
375
- const openBracket = s.indexOf("[");
376
- let startIdx = -1;
377
- let openChar = "", closeChar = "";
378
- if (openBrace === -1 && openBracket === -1) return s;
379
- if (openBrace === -1) {
380
- startIdx = openBracket;
381
- openChar = "[";
382
- closeChar = "]";
383
- } else if (openBracket === -1) {
384
- startIdx = openBrace;
385
- openChar = "{";
386
- closeChar = "}";
387
- } else if (openBrace < openBracket) {
388
- startIdx = openBrace;
389
- openChar = "{";
390
- closeChar = "}";
391
- } else {
392
- startIdx = openBracket;
393
- openChar = "[";
394
- closeChar = "]";
395
- }
396
- let depth = 0, inString = false, escape = false, end = -1;
397
- for (let i = startIdx; i < s.length; i++) {
398
- const ch = s[i];
399
- if (escape) {
400
- escape = false;
401
- continue;
402
- }
403
- if (ch === "\\" && inString) {
404
- escape = true;
405
- continue;
406
- }
407
- if (ch === '"') {
408
- inString = !inString;
409
- continue;
410
- }
411
- if (inString) continue;
412
- if (ch === openChar) depth++;
413
- else if (ch === closeChar) {
414
- depth--;
415
- if (depth === 0) {
416
- end = i;
417
- break;
418
- }
419
- }
420
- }
421
- return end !== -1 ? s.slice(startIdx, end + 1) : s;
422
- }
423
- function repairJSON(raw) {
424
- let result = "";
425
- let inString = false;
426
- let escape = false;
427
- for (let i = 0; i < raw.length; i++) {
428
- const ch = raw[i];
429
- if (escape) {
430
- result += ch;
431
- escape = false;
432
- continue;
433
- }
434
- if (ch === "\\" && inString) {
435
- result += ch;
436
- escape = true;
437
- continue;
438
- }
439
- if (ch === '"') {
440
- inString = !inString;
441
- result += ch;
442
- continue;
443
- }
444
- if (inString) {
445
- result += ch;
446
- continue;
447
- }
448
- if (ch === ",") {
449
- let j = i + 1;
450
- while (j < raw.length && /\s/.test(raw[j])) j++;
451
- if (j < raw.length && (raw[j] === "}" || raw[j] === "]")) {
452
- continue;
453
- }
454
- }
455
- result += ch;
456
- }
457
- return result;
458
- }
459
- function parseSchema(schema, raw) {
460
- const cleaned = cleanLLMOutput(raw);
461
- try {
462
- const parsed = JSON.parse(cleaned);
463
- const r = schema.safeParse(parsed);
464
- if (r.success) return { success: true, data: r.data, raw: cleaned, errors: [], attempts: 1 };
465
- return { success: false, raw: cleaned, errors: r.errors.map((e) => (e.path ? e.path + ": " : "") + e.message), attempts: 1 };
466
- } catch {
467
- const repaired = repairJSON(cleaned);
468
- if (repaired !== cleaned) {
469
- try {
470
- const parsed = JSON.parse(repaired);
471
- const r = schema.safeParse(parsed);
472
- if (r.success) return { success: true, data: r.data, raw: repaired, errors: [], attempts: 2 };
473
- return { success: false, raw: repaired, errors: r.errors.map((e) => (e.path ? e.path + ": " : "") + e.message), attempts: 2 };
474
- } catch {
475
- }
476
- }
477
- return { success: false, errors: ["Could not parse LLM output as JSON"], attempts: 2 };
478
- }
479
- }
480
- async function parseWithRetry(schema, promptFn, maxRetries = 3) {
481
- let context = "Respond with valid JSON only. No markdown fences, no explanation, just the JSON.";
482
- let totalAttempts = 0;
483
- for (let i = 0; i <= maxRetries; i++) {
484
- const raw = await promptFn(context);
485
- totalAttempts++;
486
- const result = parseSchema(schema, raw);
487
- if (result.success) return { ...result, attempts: totalAttempts };
488
- context = `Your response failed validation: ${result.errors.join("; ")}. Fix these and respond with valid JSON only.`;
489
- }
490
- return { success: false, errors: [`Max retries (${maxRetries}) exceeded`], attempts: totalAttempts };
491
- }
492
-
493
- // src/ai/mcp-server-kit.ts
494
- var ERR = { PARSE: -32700, INVALID: -32600, NOT_FOUND: -32601, PARAMS: -32602, INTERNAL: -32603 };
495
- var MAX_MESSAGE_SIZE = 10 * 1024 * 1024;
496
- var MAX_NAME_LENGTH = 256;
497
- var HANDLER_TIMEOUT_MS = 3e4;
498
- function validateToolInput(args, schema) {
499
- if (typeof args !== "object" || args === null || Array.isArray(args)) {
500
- return "Arguments must be an object";
501
- }
502
- if (schema.required) {
503
- for (const req of schema.required) {
504
- if (!(req in args) || args[req] === void 0 || args[req] === null) {
505
- return `Missing required argument: ${req}`;
506
- }
507
- }
508
- }
509
- for (const [key, val] of Object.entries(args)) {
510
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
511
- return `Invalid argument name: ${key}`;
512
- }
513
- const propSchema = schema.properties[key];
514
- if (propSchema) {
515
- const expectedType = propSchema.type;
516
- if (expectedType === "string" && typeof val !== "string") return `Argument '${key}' must be a string`;
517
- if (expectedType === "number" && typeof val !== "number") return `Argument '${key}' must be a number`;
518
- if (expectedType === "boolean" && typeof val !== "boolean") return `Argument '${key}' must be a boolean`;
519
- if (expectedType === "integer" && (typeof val !== "number" || !Number.isInteger(val))) return `Argument '${key}' must be an integer`;
520
- if (propSchema.enum && !propSchema.enum.includes(val)) return `Argument '${key}' must be one of: ${propSchema.enum.join(", ")}`;
521
- }
522
- }
523
- return null;
524
- }
525
- var MCPServerBuilder = class {
526
- constructor(name, version = "1.0.0", description = "") {
527
- this.name = name;
528
- this.version = version;
529
- this.description = description;
530
- this.tools = /* @__PURE__ */ new Map();
531
- this.resources = /* @__PURE__ */ new Map();
532
- this.prompts = /* @__PURE__ */ new Map();
533
- this.capabilities = {};
534
- this.initialized = false;
535
- if (!name || typeof name !== "string") throw new Error("Server name is required");
536
- }
537
- addTool(tool) {
538
- if (!tool.name || typeof tool.name !== "string" || tool.name.length > MAX_NAME_LENGTH) throw new Error("Tool must have a valid name");
539
- if (typeof tool.handler !== "function") throw new Error("Tool must have a handler function");
540
- if (!tool.inputSchema || tool.inputSchema.type !== "object") throw new Error("Tool must have a valid inputSchema with type: 'object'");
541
- this.tools.set(tool.name, tool);
542
- this.capabilities.tools = {};
543
- return this;
544
- }
545
- addResource(resource) {
546
- if (!resource.uri || typeof resource.uri !== "string") throw new Error("Resource must have a URI");
547
- if (typeof resource.fetch !== "function") throw new Error("Resource must have a fetch function");
548
- this.resources.set(resource.uri, resource);
549
- this.capabilities.resources = {};
550
- return this;
551
- }
552
- addPrompt(prompt) {
553
- if (!prompt.name || typeof prompt.name !== "string") throw new Error("Prompt must have a name");
554
- if (typeof prompt.handler !== "function") throw new Error("Prompt must have a handler function");
555
- this.prompts.set(prompt.name, prompt);
556
- this.capabilities.prompts = {};
557
- return this;
558
- }
559
- respond(id, result) {
560
- return JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n";
561
- }
562
- error(id, code, message, data) {
563
- return JSON.stringify({ jsonrpc: "2.0", id, error: { code, message, data } }) + "\n";
564
- }
565
- /** Run a handler with a timeout */
566
- async runWithTimeout(fn, timeoutMs) {
567
- return new Promise((resolve2, reject) => {
568
- const timer = setTimeout(() => reject(new Error("Handler execution timeout")), timeoutMs);
569
- fn().then(
570
- (result) => {
571
- clearTimeout(timer);
572
- resolve2(result);
573
- },
574
- (err) => {
575
- clearTimeout(timer);
576
- reject(err);
577
- }
578
- );
579
- });
580
- }
581
- async dispatch(req) {
582
- const { id, method, params } = req;
583
- if (req.jsonrpc !== "2.0") {
584
- if (id !== null && id !== void 0) return this.error(id, ERR.INVALID, "Invalid JSON-RPC version \u2014 must be '2.0'");
585
- return null;
586
- }
587
- if (typeof method !== "string" || method.length === 0) {
588
- if (id !== null && id !== void 0) return this.error(id, ERR.INVALID, "Method must be a non-empty string");
589
- return null;
590
- }
591
- if (method === "initialize") {
592
- this.initialized = true;
593
- return this.respond(id, {
594
- protocolVersion: "2024-11-05",
595
- capabilities: this.capabilities,
596
- serverInfo: { name: this.name, version: this.version },
597
- instructions: this.description || void 0
598
- });
599
- }
600
- if (method === "initialized") return null;
601
- if (method === "ping") return this.respond(id, {});
602
- if (method === "tools/list") {
603
- return this.respond(id, {
604
- tools: [...this.tools.values()].map((t) => ({
605
- name: t.name,
606
- description: t.description,
607
- inputSchema: t.inputSchema
608
- }))
609
- });
610
- }
611
- if (method === "tools/call") {
612
- const toolName = params?.name;
613
- if (typeof toolName !== "string") return this.error(id, ERR.PARAMS, "Tool name is required");
614
- const tool = this.tools.get(toolName);
615
- if (!tool) return this.error(id, ERR.NOT_FOUND, `Tool not found: ${toolName}`);
616
- const args = params?.arguments ?? {};
617
- const validationError = validateToolInput(args, tool.inputSchema);
618
- if (validationError) return this.error(id, ERR.PARAMS, validationError);
619
- try {
620
- const result = await this.runWithTimeout(
621
- () => tool.handler(args, { progressToken: params?._meta?.progressToken }),
622
- HANDLER_TIMEOUT_MS
623
- );
624
- const content = typeof result === "string" ? [{ type: "text", text: result }] : [{ type: "text", text: JSON.stringify(result) }];
625
- return this.respond(id, { content, isError: false });
626
- } catch (e) {
627
- const msg = e?.message ?? String(e);
628
- return this.respond(id, { content: [{ type: "text", text: msg.slice(0, 4096) }], isError: true });
629
- }
630
- }
631
- if (method === "resources/list") {
632
- return this.respond(id, {
633
- resources: [...this.resources.values()].map((r) => ({
634
- uri: r.uri,
635
- name: r.name,
636
- description: r.description,
637
- mimeType: r.mimeType
638
- }))
639
- });
640
- }
641
- if (method === "resources/read") {
642
- const uri = params?.uri;
643
- if (typeof uri !== "string") return this.error(id, ERR.PARAMS, "Resource URI is required");
644
- const resource = this.resources.get(uri);
645
- if (!resource) return this.error(id, ERR.NOT_FOUND, `Resource not found: ${uri}`);
646
- try {
647
- const raw = await this.runWithTimeout(() => resource.fetch(), HANDLER_TIMEOUT_MS);
648
- const content = typeof raw === "string" ? { uri: resource.uri, mimeType: resource.mimeType ?? "text/plain", text: raw } : { uri: resource.uri, mimeType: raw.mimeType ?? resource.mimeType ?? "text/plain", ...raw.text ? { text: raw.text } : { blob: raw.blob } };
649
- return this.respond(id, { contents: [content] });
650
- } catch (e) {
651
- return this.error(id, ERR.INTERNAL, `Resource fetch failed: ${(e?.message ?? "Unknown error").slice(0, 1024)}`);
652
- }
653
- }
654
- if (method === "prompts/list") {
655
- return this.respond(id, {
656
- prompts: [...this.prompts.values()].map((p) => ({ name: p.name, description: p.description, arguments: p.arguments }))
657
- });
658
- }
659
- if (method === "prompts/get") {
660
- const promptName = params?.name;
661
- if (typeof promptName !== "string") return this.error(id, ERR.PARAMS, "Prompt name is required");
662
- const prompt = this.prompts.get(promptName);
663
- if (!prompt) return this.error(id, ERR.NOT_FOUND, `Prompt not found: ${promptName}`);
664
- try {
665
- const messages = await this.runWithTimeout(
666
- () => prompt.handler(params?.arguments ?? {}),
667
- HANDLER_TIMEOUT_MS
668
- );
669
- return this.respond(id, { description: prompt.description, messages });
670
- } catch (e) {
671
- return this.error(id, ERR.INTERNAL, `Prompt handler failed: ${(e?.message ?? "Unknown error").slice(0, 1024)}`);
672
- }
673
- }
674
- if (id !== null && id !== void 0) return this.error(id, ERR.NOT_FOUND, `Method not found: ${method}`);
675
- return null;
676
- }
677
- startStdio() {
678
- process.stdin.setEncoding("utf-8");
679
- let buf = "";
680
- let processing = Promise.resolve();
681
- process.stdin.on("data", (chunk) => {
682
- buf += chunk;
683
- if (buf.length > MAX_MESSAGE_SIZE) {
684
- process.stdout.write(this.error(null, ERR.PARSE, "Message too large") + "\n");
685
- buf = "";
686
- return;
687
- }
688
- const lines = buf.split("\n");
689
- buf = lines.pop() ?? "";
690
- for (const line of lines) {
691
- const trimmed = line.trim();
692
- if (!trimmed) continue;
693
- processing = processing.then(async () => {
694
- let req;
695
- try {
696
- req = JSON.parse(trimmed);
697
- } catch {
698
- process.stdout.write(this.error(null, ERR.PARSE, "Parse error") + "\n");
699
- return;
700
- }
701
- if (typeof req !== "object" || req === null || Array.isArray(req)) {
702
- process.stdout.write(this.error(null, ERR.INVALID, "Request must be a JSON object") + "\n");
703
- return;
704
- }
705
- try {
706
- const response = await this.dispatch(req);
707
- if (response) process.stdout.write(response);
708
- } catch (e) {
709
- const reqId = req?.id;
710
- if (reqId !== null && reqId !== void 0) {
711
- process.stdout.write(this.error(reqId, ERR.INTERNAL, (e?.message ?? "Internal error").slice(0, 1024)) + "\n");
712
- }
713
- }
714
- });
715
- }
716
- });
717
- process.stdin.on("end", () => process.exit(0));
718
- process.stderr.write(`[devguard/mcp] "${this.name}" v${this.version} started
719
- `);
720
- }
721
- };
722
- var FileSystemAdapter = class {
723
- constructor(dir = ".devguard-memory") {
724
- this.keyIndex = /* @__PURE__ */ new Map();
725
- this.baseDir = path__namespace.resolve(dir);
726
- if (!fs__namespace.existsSync(this.baseDir)) {
727
- fs__namespace.mkdirSync(this.baseDir, { recursive: true });
728
- }
729
- }
730
- getFilePath(agentId) {
731
- const safeId = crypto__namespace.createHash("sha256").update(agentId).digest("hex");
732
- return path__namespace.join(this.baseDir, `${safeId}.json`);
733
- }
734
- async save(agentId, entry) {
735
- const file = this.getFilePath(agentId);
736
- let history = [];
737
- if (fs__namespace.existsSync(file)) {
738
- try {
739
- const raw = fs__namespace.readFileSync(file, "utf-8");
740
- history = JSON.parse(raw);
741
- if (!Array.isArray(history)) history = [];
742
- } catch {
743
- history = [];
744
- }
745
- }
746
- history.push(entry);
747
- const tmp = `${file}.tmp.${crypto__namespace.randomBytes(4).toString("hex")}`;
748
- fs__namespace.writeFileSync(tmp, JSON.stringify(history, null, 2));
749
- fs__namespace.renameSync(tmp, file);
750
- }
751
- async getHistory(agentId, limit = 50) {
752
- const file = this.getFilePath(agentId);
753
- if (!fs__namespace.existsSync(file)) return [];
754
- try {
755
- const raw = fs__namespace.readFileSync(file, "utf-8");
756
- const history = JSON.parse(raw);
757
- if (!Array.isArray(history)) return [];
758
- return history.slice(-limit);
759
- } catch {
760
- return [];
761
- }
762
- }
763
- async clear(agentId) {
764
- const file = this.getFilePath(agentId);
765
- if (fs__namespace.existsSync(file)) fs__namespace.unlinkSync(file);
766
- }
767
- };
768
- var RedisAdapter = class {
769
- constructor(redisClient) {
770
- this.client = redisClient;
771
- }
772
- async save(agentId, entry) {
773
- const key = `devguard:mem:${agentId}`;
774
- await this.client.rPush(key, JSON.stringify(entry));
775
- await this.client.lTrim(key, -100, -1);
776
- }
777
- async getHistory(agentId, limit = 50) {
778
- const key = `devguard:mem:${agentId}`;
779
- const raw = await this.client.lRange(key, -limit, -1);
780
- return raw.map((r) => {
781
- try {
782
- return JSON.parse(r);
783
- } catch {
784
- return null;
785
- }
786
- }).filter(Boolean);
787
- }
788
- async clear(agentId) {
789
- await this.client.del(`devguard:mem:${agentId}`);
790
- }
791
- };
792
- var AgentMemory = class {
793
- constructor(adapter) {
794
- this.adapter = adapter ?? new FileSystemAdapter();
795
- }
796
- async track(agentId, role, content, metadata) {
797
- const entry = {
798
- id: crypto__namespace.randomUUID(),
799
- role,
800
- content,
801
- metadata,
802
- timestamp: Date.now()
803
- };
804
- await this.adapter.save(agentId, entry);
805
- return entry;
806
- }
807
- async getContext(agentId, limit = 10) {
808
- const history = await this.adapter.getHistory(agentId, limit);
809
- return history.map((h) => `${h.role.toUpperCase()}: ${h.content}`).join("\n");
810
- }
811
- async clear(agentId) {
812
- await this.adapter.clear(agentId);
813
- }
814
- };
815
- var MAX_RECORDS = 5e3;
816
- var LLMBudget = class {
817
- constructor(config) {
818
- this.records = [];
819
- this.totalCost = 0;
820
- this.config = config;
821
- }
822
- track(usage) {
823
- const record = {
824
- ...usage,
825
- id: crypto__namespace.randomUUID(),
826
- timestamp: Date.now()
827
- };
828
- this.records.push(record);
829
- this.totalCost += record.costUSD;
830
- if (this.records.length > MAX_RECORDS) {
831
- this.records.shift();
832
- }
833
- if (this.totalCost >= this.config.monthlyLimitUSD) {
834
- console.warn(`[devguard] LLM Budget Exceeded: $${this.totalCost.toFixed(4)} / $${this.config.monthlyLimitUSD}`);
835
- } else if (this.config.warnAtUSD && this.totalCost >= this.config.warnAtUSD) {
836
- console.warn(`[devguard] LLM Budget Warning: $${this.totalCost.toFixed(4)} / $${this.config.monthlyLimitUSD}`);
837
- }
838
- return record;
839
- }
840
- getSummary() {
841
- return {
842
- totalCost: this.totalCost,
843
- recordCount: this.records.length,
844
- limit: this.config.monthlyLimitUSD,
845
- remaining: Math.max(0, this.config.monthlyLimitUSD - this.totalCost),
846
- isExceeded: this.totalCost >= this.config.monthlyLimitUSD
847
- };
848
- }
849
- getHistory(limit = 100) {
850
- return this.records.slice(-limit);
851
- }
852
- reset() {
853
- this.records = [];
854
- this.totalCost = 0;
855
- }
856
- };
857
-
858
- exports.AgentMemory = AgentMemory;
859
- exports.FileSystemAdapter = FileSystemAdapter;
860
- exports.LLMBudget = LLMBudget;
861
- exports.MCPServerBuilder = MCPServerBuilder;
862
- exports.RedisAdapter = RedisAdapter;
863
- exports.c = c;
864
- exports.cleanLLMOutput = cleanLLMOutput;
865
- exports.parseSchema = parseSchema;
866
- exports.parseWithRetry = parseWithRetry;
867
- exports.s = c;