🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@eldrex/gateway

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eldrex/gateway - npm Package Compare versions

Comparing version
1.0.0
to
1.0.2
+269
-102
dist/index.cjs

@@ -57,2 +57,3 @@ "use strict";

MermaidSanitizer: () => MermaidSanitizer,
OUTPUT_FORMATS: () => OUTPUT_FORMATS,
PersonaProcessor: () => PersonaProcessor,

@@ -96,3 +97,6 @@ PriorityQueue: () => PriorityQueue,

async handle(req, res) {
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
const url = new URL(
req.url || "/",
`http://${req.headers.host || "localhost"}`
);
const pathname = url.pathname;

@@ -113,3 +117,7 @@ const method = (req.method || "GET").toUpperCase();

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: `Internal Server Error: ${err.message}` }));
res.end(
JSON.stringify({
error: `Internal Server Error: ${err.message}`
})
);
}

@@ -148,3 +156,5 @@ return true;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: "Unauthorized: Invalid or missing API key." }));
res.end(
JSON.stringify({ error: "Unauthorized: Invalid or missing API key." })
);
return false;

@@ -192,3 +202,5 @@ }

res.setHeader("Retry-After", "60");
res.end(JSON.stringify({ error: "Too Many Requests: Rate limit exceeded." }));
res.end(
JSON.stringify({ error: "Too Many Requests: Rate limit exceeded." })
);
return false;

@@ -223,7 +235,9 @@ }

}).optional(),
outputs: import_zod.z.array(import_zod.z.object({
type: import_zod.z.string(),
destination: import_zod.z.string(),
config: import_zod.z.record(import_zod.z.any()).optional()
})).optional()
outputs: import_zod.z.array(
import_zod.z.object({
type: import_zod.z.string(),
destination: import_zod.z.string(),
config: import_zod.z.record(import_zod.z.any()).optional()
})
).optional()
});

@@ -234,3 +248,10 @@ var CustomPersonaConfigSchema = import_zod.z.object({

name: import_zod.z.string().optional(),
tone: import_zod.z.enum(["formal", "casual", "technical", "executive", "educational", "robotic"]).optional(),
tone: import_zod.z.enum([
"formal",
"casual",
"technical",
"executive",
"educational",
"robotic"
]).optional(),
verbosity: import_zod.z.number().min(1).max(5).optional(),

@@ -255,3 +276,5 @@ focus: import_zod.z.array(import_zod.z.string()).optional(),

success: false,
errors: result.error.errors.map((err) => `${err.path.join(".")}: ${err.message}`)
errors: result.error.errors.map(
(err) => `${err.path.join(".")}: ${err.message}`
)
};

@@ -417,3 +440,5 @@ }

if (!step) {
throw new Error(`Pipeline references unregistered step: ${stepConfig.step}`);
throw new Error(
`Pipeline references unregistered step: ${stepConfig.step}`
);
}

@@ -500,4 +525,6 @@ await step.run(context, stepConfig.config || {});

const redactedCode = (0, import_core.redactSecrets)(contextCode);
processedFiles.push(`--- File: ${fileDiff.newPath || fileDiff.oldPath} ---
${redactedCode}`);
processedFiles.push(
`--- File: ${fileDiff.newPath || fileDiff.oldPath} ---
${redactedCode}`
);
}

@@ -551,3 +578,6 @@ context.astContext = processedFiles.join("\n\n");

}
const transformedSummary = import_personas.PersonaEngine.postProcess(rawResponse.summary, persona);
const transformedSummary = import_personas.PersonaEngine.postProcess(
rawResponse.summary,
persona
);
const transformedFiles = (rawResponse.files || []).map((file) => ({

@@ -661,16 +691,21 @@ path: file.path,

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({
gateway: "active",
connections: this.activeSockets.size,
personas: import_personas2.PersonaRegistry.list().map((p) => p.id),
skills: SkillRegistry.list().map((s) => s.name),
watchers: {
git: this.gitWatchers.length,
filesystem: this.fsWatchers.length
}
}));
res.end(
JSON.stringify({
gateway: "active",
connections: this.activeSockets.size,
personas: import_personas2.PersonaRegistry.list().map((p) => p.id),
skills: SkillRegistry.list().map((s) => s.name),
watchers: {
git: this.gitWatchers.length,
filesystem: this.fsWatchers.length
}
})
);
});
this.router.addRoute("POST", "/api/v1/analyze", async (req, res) => {
const body = await this.readBody(req);
const parseResult = ValidationMiddleware.validate(DevDiffEventSchema, body);
const parseResult = ValidationMiddleware.validate(
DevDiffEventSchema,
body
);
if (!parseResult.success) {

@@ -703,18 +738,23 @@ res.statusCode = 400;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({
event_id: event.id || "generated-id",
status: "completed",
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
processing_time_ms: duration,
results: {
changelog: resultContext.outputs?.["markdown"] || "",
markdown: resultContext.outputs?.["markdown"] || "",
json: resultContext.outputs?.["json"] || {},
stats: {
files_changed: resultContext.aiRawResponse?.files?.length || 0,
breaking_changes: resultContext.aiRawResponse?.breaking ? 1 : 0
res.end(
JSON.stringify({
event_id: event.id || "generated-id",
status: "completed",
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
processing_time_ms: duration,
results: {
changelog: resultContext.outputs?.["markdown"] || "",
markdown: resultContext.outputs?.["markdown"] || "",
json: resultContext.outputs?.["json"] || {},
stats: {
files_changed: resultContext.aiRawResponse?.files?.length || 0,
breaking_changes: resultContext.aiRawResponse?.breaking ? 1 : 0
}
}
}
}));
this.broadcast("changelog_generated", resultContext.aiFormattedResponse);
})
);
this.broadcast(
"changelog_generated",
resultContext.aiFormattedResponse
);
} catch (err) {

@@ -741,7 +781,11 @@ res.statusCode = 500;

});
this.router.addRoute("POST", "/webhooks/custom/:name", async (req, res, params) => {
const body = await this.readBody(req);
const parsed = CustomWebhookParser.parse(req.headers, body);
this.handleWebhookEvent(parsed, res);
});
this.router.addRoute(
"POST",
"/webhooks/custom/:name",
async (req, res, params) => {
const body = await this.readBody(req);
const parsed = CustomWebhookParser.parse(req.headers, body);
this.handleWebhookEvent(parsed, res);
}
);
this.router.addRoute("GET", "/api/v1/personas", (req, res) => {

@@ -762,3 +806,5 @@ res.statusCode = 200;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: "Unsupported or unparseable webhook event." }));
res.end(
JSON.stringify({ error: "Unsupported or unparseable webhook event." })
);
return;

@@ -824,4 +870,10 @@ }

res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, DELETE"
);
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, X-API-Key"
);
if (req.method === "OPTIONS") {

@@ -853,19 +905,27 @@ res.statusCode = 204;

if (method === "tools/list") {
res.end(JSON.stringify({
result: {
tools: [
{
name: "devdiff_analyze",
description: "Analyzes code changes and returns persona-aware explanation.",
inputSchema: {
type: "object",
properties: {
range: { type: "string", description: "Git revision range" },
persona: { type: "string", description: "AI output persona" }
res.end(
JSON.stringify({
result: {
tools: [
{
name: "devdiff_analyze",
description: "Analyzes code changes and returns persona-aware explanation.",
inputSchema: {
type: "object",
properties: {
range: {
type: "string",
description: "Git revision range"
},
persona: {
type: "string",
description: "AI output persona"
}
}
}
}
}
]
}
}));
]
}
})
);
} else if (method === "tools/call") {

@@ -875,3 +935,6 @@ const args = body.params?.arguments || {};

repoPath: this.config.repoPath,
change_range: args.range ? { from: args.range.split("..")[0], to: args.range.split("..")[1] } : void 0,
change_range: args.range ? {
from: args.range.split("..")[0],
to: args.range.split("..")[1]
} : void 0,
personaId: args.persona || "developer",

@@ -888,12 +951,14 @@ formats: ["markdown"]

]);
res.end(JSON.stringify({
result: {
content: [
{
type: "text",
text: resultContext.outputs?.["markdown"] || "No explanation generated."
}
]
}
}));
res.end(
JSON.stringify({
result: {
content: [
{
type: "text",
text: resultContext.outputs?.["markdown"] || "No explanation generated."
}
]
}
})
);
} catch (err) {

@@ -914,7 +979,9 @@ res.end(JSON.stringify({ error: err.message }));

const body = await this.readBody(req);
res.end(JSON.stringify({
status: "success",
pipeline: body.skill || "devdiff",
processedAt: (/* @__PURE__ */ new Date()).toISOString()
}));
res.end(
JSON.stringify({
status: "success",
pipeline: body.skill || "devdiff",
processedAt: (/* @__PURE__ */ new Date()).toISOString()
})
);
} else {

@@ -933,3 +1000,5 @@ res.statusCode = 405;

new Promise((resolve2) => this.mcpServer.listen(mcpPort, resolve2)),
new Promise((resolve2) => this.openclawServer.listen(openclawPort, resolve2)),
new Promise(
(resolve2) => this.openclawServer.listen(openclawPort, resolve2)
),
new Promise((resolve2) => this.grpcServer.listen(grpcPort, resolve2))

@@ -951,3 +1020,5 @@ ]);

new Promise((resolve2) => this.mcpServer.close(() => resolve2())),
new Promise((resolve2) => this.openclawServer.close(() => resolve2())),
new Promise(
(resolve2) => this.openclawServer.close(() => resolve2())
),
new Promise((resolve2) => this.grpcServer.close(() => resolve2()))

@@ -1137,6 +1208,6 @@ ]);

const arrows = {
"arrow": "-->",
"open": "---",
"dotted": "-.->",
"thick": "==>"
arrow: "-->",
open: "---",
dotted: "-.->",
thick: "==>"
};

@@ -1153,3 +1224,5 @@ return `${fromId} ${edgeLabel}${arrows[type]} ${toId}`;

if (openBrackets !== closeBrackets) {
errors.push(`Bracket mismatch: ${openBrackets} open, ${closeBrackets} close`);
errors.push(
`Bracket mismatch: ${openBrackets} open, ${closeBrackets} close`
);
}

@@ -1198,4 +1271,8 @@ const quotes = diagram.match(/"/g) || [];

lines.push(` ${parentNode}[${MermaidSanitizer.toLabel(c.summary)}]`);
lines.push(` ${targetNode}[${MermaidSanitizer.toLabel(c.affectedModule)}]`);
lines.push(` ${parentNode} --> |${MermaidSanitizer.toLabel(c.impact)}| ${targetNode}`);
lines.push(
` ${targetNode}[${MermaidSanitizer.toLabel(c.affectedModule)}]`
);
lines.push(
` ${parentNode} --> |${MermaidSanitizer.toLabel(c.impact)}| ${targetNode}`
);
lines.push(` style ${parentNode} fill:${this.getColor(c.type)}`);

@@ -1229,3 +1306,5 @@ });

if (beforeKeys.length > 0 && afterKeys.length > 0) {
lines.push(` ${MermaidSanitizer.toNodeId(`B_${beforeKeys[0]}`)} -.-> |"refactored to"| ${MermaidSanitizer.toNodeId(`A_${afterKeys[0]}`)}`);
lines.push(
` ${MermaidSanitizer.toNodeId(`B_${beforeKeys[0]}`)} -.-> |"refactored to"| ${MermaidSanitizer.toNodeId(`A_${afterKeys[0]}`)}`
);
}

@@ -1240,3 +1319,5 @@ }

const packageLabel = `${d.package}@${d.version}`;
lines.push(` ${packageNode}[${MermaidSanitizer.toLabel(packageLabel)}]`);
lines.push(
` ${packageNode}[${MermaidSanitizer.toLabel(packageLabel)}]`
);
d.dependents.forEach((dep) => {

@@ -1266,3 +1347,5 @@ const depNode = MermaidSanitizer.toNodeId(dep);

const safeName = f.name.replace(/:/g, "_");
lines.push(` ${MermaidSanitizer.toLabel(safeName)}: [${f.frequency}, ${f.complexity}]`);
lines.push(
` ${MermaidSanitizer.toLabel(safeName)}: [${f.frequency}, ${f.complexity}]`
);
});

@@ -1326,3 +1409,8 @@ return this.wrapAndValidate(lines.join("\n"));

let progress = 0;
const stages = ["Parsing diffs", "AST analysis", "AI processing", "Generating outputs"];
const stages = [
"Parsing diffs",
"AST analysis",
"AI processing",
"Generating outputs"
];
for await (const result of generator) {

@@ -1423,3 +1511,6 @@ progress = result.progress || progress;

this.createdAt = Date.now();
this.repository = { path: event.repository.path, branch: event.repository.branch };
this.repository = {
path: event.repository.path,
branch: event.repository.branch
};
this.events = [event];

@@ -1455,3 +1546,6 @@ this.config = { batchWindow: event.config.batchWindow || 3e5 };

queue.enqueue(batch, this.calculatePriority(event));
const totalQueueSize = Array.from(this.repoQueues.values()).reduce((acc, q) => acc + q.size(), 0);
const totalQueueSize = Array.from(this.repoQueues.values()).reduce(
(acc, q) => acc + q.size(),
0
);
if (totalQueueSize > this.config.backpressureThreshold) {

@@ -1505,6 +1599,13 @@ this.emit("backpressure:activate");

async processBatch(batch) {
return new Promise((resolve2) => setTimeout(() => resolve2({ success: true, processedEvents: batch.events.length }), 100));
return new Promise(
(resolve2) => setTimeout(
() => resolve2({ success: true, processedEvents: batch.events.length }),
100
)
);
}
timeout(ms, message) {
return new Promise((_, reject) => setTimeout(() => reject(new Error(message)), ms));
return new Promise(
(_, reject) => setTimeout(() => reject(new Error(message)), ms)
);
}

@@ -1521,5 +1622,10 @@ getJob(id) {

constructor(config) {
console.log(`[BullMQ] Initializing Redis-backed queue on ${config.redis.host}:${config.redis.port}`);
console.log(
`[BullMQ] Initializing Redis-backed queue on ${config.redis.host}:${config.redis.port}`
);
this.init(config).catch((err) => {
console.warn("[BullMQ] Initialization failed, running in fallback mode:", err.message);
console.warn(
"[BullMQ] Initialization failed, running in fallback mode:",
err.message
);
});

@@ -1560,3 +1666,5 @@ }

} catch {
console.warn("[BullMQ] bullmq package not installed. Running in mock/fallback mode.");
console.warn(
"[BullMQ] bullmq package not installed. Running in mock/fallback mode."
);
}

@@ -1758,3 +1866,5 @@ }

if (!match) {
throw new Error("Invalid SKILL.md structure: Frontmatter separators (---) missing.");
throw new Error(
"Invalid SKILL.md structure: Frontmatter separators (---) missing."
);
}

@@ -1765,3 +1875,5 @@ const frontmatterRaw = match[1];

if (!parsed.name || !parsed.version) {
throw new Error("SKILL.md frontmatter must contain 'name' and 'version'.");
throw new Error(
"SKILL.md frontmatter must contain 'name' and 'version'."
);
}

@@ -1788,2 +1900,56 @@ return {

};
// src/outputs/formats.ts
var OUTPUT_FORMATS = {
markdown: {
name: "Markdown",
extension: ".md",
mimeType: "text/markdown"
},
mermaid: {
name: "Mermaid Diagram",
extension: ".mmd",
mimeType: "text/plain",
sanitize: true
// Strict ID sanitization
},
json: {
name: "JSON",
extension: ".json",
mimeType: "application/json"
},
slack: {
name: "Slack Message",
channel: true,
streaming: true
// Progressive updates
},
discord: {
name: "Discord Message",
channel: true,
streaming: true
},
teams: {
name: "Microsoft Teams",
channel: true
},
email: {
name: "Email",
smtp: true
},
notion: {
name: "Notion Page",
api: true,
append: true
},
confluence: {
name: "Confluence Page",
api: true
},
obsidian: {
name: "Obsidian Vault",
extension: ".md",
vault: true
}
};
// Annotate the CommonJS export names for ESM import in node:

@@ -1815,2 +1981,3 @@ 0 && (module.exports = {

MermaidSanitizer,
OUTPUT_FORMATS,
PersonaProcessor,

@@ -1817,0 +1984,0 @@ PriorityQueue,

@@ -355,3 +355,3 @@ import { IncomingMessage, ServerResponse } from 'http';

affectedModule: string;
type: 'feature' | 'fix' | 'refactor' | 'docs' | 'test' | 'chore' | 'breaking' | 'security';
type: "feature" | "fix" | "refactor" | "docs" | "test" | "chore" | "breaking" | "security";
}

@@ -419,3 +419,3 @@ interface DependencyChange {

*/
static edge(from: string, to: string, type?: 'arrow' | 'open' | 'dotted' | 'thick', label?: string): string;
static edge(from: string, to: string, type?: "arrow" | "open" | "dotted" | "thick", label?: string): string;
/**

@@ -437,3 +437,3 @@ * Validate entire diagram before output

timestamp: string;
source: 'git' | 'webhook' | 'api' | 'schedule' | 'manual';
source: "git" | "webhook" | "api" | "schedule" | "manual";
gateway_version?: string;

@@ -454,5 +454,5 @@ repository: {

formats: string[];
depth?: 'minimal' | 'standard' | 'deep' | 'exhaustive';
depth?: "minimal" | "standard" | "deep" | "exhaustive";
language?: string;
ai_routing?: 'local' | 'cloud' | 'auto';
ai_routing?: "local" | "cloud" | "auto";
batchWindow?: number;

@@ -462,3 +462,3 @@ };

interface QueueConfig {
strategy: 'per-repo-sequential' | 'global-fifo' | 'priority';
strategy: "per-repo-sequential" | "global-fifo" | "priority";
maxConcurrent: number;

@@ -621,3 +621,3 @@ maxConcurrentPerRepo: number;

author: string;
triggers: ('git_push' | 'pull_request' | 'scheduled' | 'manual' | 'webhook')[];
triggers: ("git_push" | "pull_request" | "scheduled" | "manual" | "webhook")[];
inputs: Record<string, {

@@ -640,3 +640,3 @@ type: string;

bodyMarkdown: string;
difficulty?: 'beginner' | 'intermediate' | 'advanced';
difficulty?: "beginner" | "intermediate" | "advanced";
estimated_tokens_per_run?: number;

@@ -664,2 +664,53 @@ tags?: string[];

export { AIProcessor, ASTProcessor, AuthMiddleware, Batch, type BullMQConfig, BullMQQueueAdapter, type ChangeStats, type Commit, type CustomOutputPlugin, CustomOutputter, CustomPersonaConfigSchema, CustomWebhookParser, type DataFlow, type DependencyChange, type DevDiffEvent, DevDiffEventSchema, DevDiffGateway, DiffProcessor, type DiscordConfig, DiscordOutputter, type EmailConfig, EmailOutputter, FormatProcessor, FsWatcher, type FsWatcherConfig, type GatewayConfig, GatewayRouter, GitHubWebhookParser, GitLabWebhookParser, GitWatcher, type GitWatcherConfig, JSONOutputter, LinearWebhookParser, MarkdownOutputter, MermaidGenerator, MermaidSanitizer, type PartialResult, PersonaProcessor, type PipelineStep, PriorityQueue, type ProcessedChange, type ProcessorContext, ProcessorPipeline, type QueueConfig, type Route, type RouteHandler, Semaphore, type SkillDefinition, SkillLoader, SkillRegistry, type SlackConfig, SlackOutputter, SlackStreamingOutputter, type TeamsConfig, TeamsOutputter, TieredQueueEngine, TokenBucketLimiter, ValidationMiddleware, type WebhookConfig, WebhookOutputter };
declare const OUTPUT_FORMATS: {
markdown: {
name: string;
extension: string;
mimeType: string;
};
mermaid: {
name: string;
extension: string;
mimeType: string;
sanitize: boolean;
};
json: {
name: string;
extension: string;
mimeType: string;
};
slack: {
name: string;
channel: boolean;
streaming: boolean;
};
discord: {
name: string;
channel: boolean;
streaming: boolean;
};
teams: {
name: string;
channel: boolean;
};
email: {
name: string;
smtp: boolean;
};
notion: {
name: string;
api: boolean;
append: boolean;
};
confluence: {
name: string;
api: boolean;
};
obsidian: {
name: string;
extension: string;
vault: boolean;
};
};
export { AIProcessor, ASTProcessor, AuthMiddleware, Batch, type BullMQConfig, BullMQQueueAdapter, type ChangeStats, type Commit, type CustomOutputPlugin, CustomOutputter, CustomPersonaConfigSchema, CustomWebhookParser, type DataFlow, type DependencyChange, type DevDiffEvent, DevDiffEventSchema, DevDiffGateway, DiffProcessor, type DiscordConfig, DiscordOutputter, type EmailConfig, EmailOutputter, FormatProcessor, FsWatcher, type FsWatcherConfig, type GatewayConfig, GatewayRouter, GitHubWebhookParser, GitLabWebhookParser, GitWatcher, type GitWatcherConfig, JSONOutputter, LinearWebhookParser, MarkdownOutputter, MermaidGenerator, MermaidSanitizer, OUTPUT_FORMATS, type PartialResult, PersonaProcessor, type PipelineStep, PriorityQueue, type ProcessedChange, type ProcessorContext, ProcessorPipeline, type QueueConfig, type Route, type RouteHandler, Semaphore, type SkillDefinition, SkillLoader, SkillRegistry, type SlackConfig, SlackOutputter, SlackStreamingOutputter, type TeamsConfig, TeamsOutputter, TieredQueueEngine, TokenBucketLimiter, ValidationMiddleware, type WebhookConfig, WebhookOutputter };

@@ -355,3 +355,3 @@ import { IncomingMessage, ServerResponse } from 'http';

affectedModule: string;
type: 'feature' | 'fix' | 'refactor' | 'docs' | 'test' | 'chore' | 'breaking' | 'security';
type: "feature" | "fix" | "refactor" | "docs" | "test" | "chore" | "breaking" | "security";
}

@@ -419,3 +419,3 @@ interface DependencyChange {

*/
static edge(from: string, to: string, type?: 'arrow' | 'open' | 'dotted' | 'thick', label?: string): string;
static edge(from: string, to: string, type?: "arrow" | "open" | "dotted" | "thick", label?: string): string;
/**

@@ -437,3 +437,3 @@ * Validate entire diagram before output

timestamp: string;
source: 'git' | 'webhook' | 'api' | 'schedule' | 'manual';
source: "git" | "webhook" | "api" | "schedule" | "manual";
gateway_version?: string;

@@ -454,5 +454,5 @@ repository: {

formats: string[];
depth?: 'minimal' | 'standard' | 'deep' | 'exhaustive';
depth?: "minimal" | "standard" | "deep" | "exhaustive";
language?: string;
ai_routing?: 'local' | 'cloud' | 'auto';
ai_routing?: "local" | "cloud" | "auto";
batchWindow?: number;

@@ -462,3 +462,3 @@ };

interface QueueConfig {
strategy: 'per-repo-sequential' | 'global-fifo' | 'priority';
strategy: "per-repo-sequential" | "global-fifo" | "priority";
maxConcurrent: number;

@@ -621,3 +621,3 @@ maxConcurrentPerRepo: number;

author: string;
triggers: ('git_push' | 'pull_request' | 'scheduled' | 'manual' | 'webhook')[];
triggers: ("git_push" | "pull_request" | "scheduled" | "manual" | "webhook")[];
inputs: Record<string, {

@@ -640,3 +640,3 @@ type: string;

bodyMarkdown: string;
difficulty?: 'beginner' | 'intermediate' | 'advanced';
difficulty?: "beginner" | "intermediate" | "advanced";
estimated_tokens_per_run?: number;

@@ -664,2 +664,53 @@ tags?: string[];

export { AIProcessor, ASTProcessor, AuthMiddleware, Batch, type BullMQConfig, BullMQQueueAdapter, type ChangeStats, type Commit, type CustomOutputPlugin, CustomOutputter, CustomPersonaConfigSchema, CustomWebhookParser, type DataFlow, type DependencyChange, type DevDiffEvent, DevDiffEventSchema, DevDiffGateway, DiffProcessor, type DiscordConfig, DiscordOutputter, type EmailConfig, EmailOutputter, FormatProcessor, FsWatcher, type FsWatcherConfig, type GatewayConfig, GatewayRouter, GitHubWebhookParser, GitLabWebhookParser, GitWatcher, type GitWatcherConfig, JSONOutputter, LinearWebhookParser, MarkdownOutputter, MermaidGenerator, MermaidSanitizer, type PartialResult, PersonaProcessor, type PipelineStep, PriorityQueue, type ProcessedChange, type ProcessorContext, ProcessorPipeline, type QueueConfig, type Route, type RouteHandler, Semaphore, type SkillDefinition, SkillLoader, SkillRegistry, type SlackConfig, SlackOutputter, SlackStreamingOutputter, type TeamsConfig, TeamsOutputter, TieredQueueEngine, TokenBucketLimiter, ValidationMiddleware, type WebhookConfig, WebhookOutputter };
declare const OUTPUT_FORMATS: {
markdown: {
name: string;
extension: string;
mimeType: string;
};
mermaid: {
name: string;
extension: string;
mimeType: string;
sanitize: boolean;
};
json: {
name: string;
extension: string;
mimeType: string;
};
slack: {
name: string;
channel: boolean;
streaming: boolean;
};
discord: {
name: string;
channel: boolean;
streaming: boolean;
};
teams: {
name: string;
channel: boolean;
};
email: {
name: string;
smtp: boolean;
};
notion: {
name: string;
api: boolean;
append: boolean;
};
confluence: {
name: string;
api: boolean;
};
obsidian: {
name: string;
extension: string;
vault: boolean;
};
};
export { AIProcessor, ASTProcessor, AuthMiddleware, Batch, type BullMQConfig, BullMQQueueAdapter, type ChangeStats, type Commit, type CustomOutputPlugin, CustomOutputter, CustomPersonaConfigSchema, CustomWebhookParser, type DataFlow, type DependencyChange, type DevDiffEvent, DevDiffEventSchema, DevDiffGateway, DiffProcessor, type DiscordConfig, DiscordOutputter, type EmailConfig, EmailOutputter, FormatProcessor, FsWatcher, type FsWatcherConfig, type GatewayConfig, GatewayRouter, GitHubWebhookParser, GitLabWebhookParser, GitWatcher, type GitWatcherConfig, JSONOutputter, LinearWebhookParser, MarkdownOutputter, MermaidGenerator, MermaidSanitizer, OUTPUT_FORMATS, type PartialResult, PersonaProcessor, type PipelineStep, PriorityQueue, type ProcessedChange, type ProcessorContext, ProcessorPipeline, type QueueConfig, type Route, type RouteHandler, Semaphore, type SkillDefinition, SkillLoader, SkillRegistry, type SlackConfig, SlackOutputter, SlackStreamingOutputter, type TeamsConfig, TeamsOutputter, TieredQueueEngine, TokenBucketLimiter, ValidationMiddleware, type WebhookConfig, WebhookOutputter };

@@ -23,3 +23,6 @@ // src/server.ts

async handle(req, res) {
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
const url = new URL(
req.url || "/",
`http://${req.headers.host || "localhost"}`
);
const pathname = url.pathname;

@@ -40,3 +43,7 @@ const method = (req.method || "GET").toUpperCase();

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: `Internal Server Error: ${err.message}` }));
res.end(
JSON.stringify({
error: `Internal Server Error: ${err.message}`
})
);
}

@@ -75,3 +82,5 @@ return true;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: "Unauthorized: Invalid or missing API key." }));
res.end(
JSON.stringify({ error: "Unauthorized: Invalid or missing API key." })
);
return false;

@@ -119,3 +128,5 @@ }

res.setHeader("Retry-After", "60");
res.end(JSON.stringify({ error: "Too Many Requests: Rate limit exceeded." }));
res.end(
JSON.stringify({ error: "Too Many Requests: Rate limit exceeded." })
);
return false;

@@ -150,7 +161,9 @@ }

}).optional(),
outputs: z.array(z.object({
type: z.string(),
destination: z.string(),
config: z.record(z.any()).optional()
})).optional()
outputs: z.array(
z.object({
type: z.string(),
destination: z.string(),
config: z.record(z.any()).optional()
})
).optional()
});

@@ -161,3 +174,10 @@ var CustomPersonaConfigSchema = z.object({

name: z.string().optional(),
tone: z.enum(["formal", "casual", "technical", "executive", "educational", "robotic"]).optional(),
tone: z.enum([
"formal",
"casual",
"technical",
"executive",
"educational",
"robotic"
]).optional(),
verbosity: z.number().min(1).max(5).optional(),

@@ -182,3 +202,5 @@ focus: z.array(z.string()).optional(),

success: false,
errors: result.error.errors.map((err) => `${err.path.join(".")}: ${err.message}`)
errors: result.error.errors.map(
(err) => `${err.path.join(".")}: ${err.message}`
)
};

@@ -344,3 +366,5 @@ }

if (!step) {
throw new Error(`Pipeline references unregistered step: ${stepConfig.step}`);
throw new Error(
`Pipeline references unregistered step: ${stepConfig.step}`
);
}

@@ -427,4 +451,6 @@ await step.run(context, stepConfig.config || {});

const redactedCode = redactSecrets(contextCode);
processedFiles.push(`--- File: ${fileDiff.newPath || fileDiff.oldPath} ---
${redactedCode}`);
processedFiles.push(
`--- File: ${fileDiff.newPath || fileDiff.oldPath} ---
${redactedCode}`
);
}

@@ -478,3 +504,6 @@ context.astContext = processedFiles.join("\n\n");

}
const transformedSummary = PersonaEngine.postProcess(rawResponse.summary, persona);
const transformedSummary = PersonaEngine.postProcess(
rawResponse.summary,
persona
);
const transformedFiles = (rawResponse.files || []).map((file) => ({

@@ -588,16 +617,21 @@ path: file.path,

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({
gateway: "active",
connections: this.activeSockets.size,
personas: PersonaRegistry2.list().map((p) => p.id),
skills: SkillRegistry.list().map((s) => s.name),
watchers: {
git: this.gitWatchers.length,
filesystem: this.fsWatchers.length
}
}));
res.end(
JSON.stringify({
gateway: "active",
connections: this.activeSockets.size,
personas: PersonaRegistry2.list().map((p) => p.id),
skills: SkillRegistry.list().map((s) => s.name),
watchers: {
git: this.gitWatchers.length,
filesystem: this.fsWatchers.length
}
})
);
});
this.router.addRoute("POST", "/api/v1/analyze", async (req, res) => {
const body = await this.readBody(req);
const parseResult = ValidationMiddleware.validate(DevDiffEventSchema, body);
const parseResult = ValidationMiddleware.validate(
DevDiffEventSchema,
body
);
if (!parseResult.success) {

@@ -630,18 +664,23 @@ res.statusCode = 400;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({
event_id: event.id || "generated-id",
status: "completed",
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
processing_time_ms: duration,
results: {
changelog: resultContext.outputs?.["markdown"] || "",
markdown: resultContext.outputs?.["markdown"] || "",
json: resultContext.outputs?.["json"] || {},
stats: {
files_changed: resultContext.aiRawResponse?.files?.length || 0,
breaking_changes: resultContext.aiRawResponse?.breaking ? 1 : 0
res.end(
JSON.stringify({
event_id: event.id || "generated-id",
status: "completed",
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
processing_time_ms: duration,
results: {
changelog: resultContext.outputs?.["markdown"] || "",
markdown: resultContext.outputs?.["markdown"] || "",
json: resultContext.outputs?.["json"] || {},
stats: {
files_changed: resultContext.aiRawResponse?.files?.length || 0,
breaking_changes: resultContext.aiRawResponse?.breaking ? 1 : 0
}
}
}
}));
this.broadcast("changelog_generated", resultContext.aiFormattedResponse);
})
);
this.broadcast(
"changelog_generated",
resultContext.aiFormattedResponse
);
} catch (err) {

@@ -668,7 +707,11 @@ res.statusCode = 500;

});
this.router.addRoute("POST", "/webhooks/custom/:name", async (req, res, params) => {
const body = await this.readBody(req);
const parsed = CustomWebhookParser.parse(req.headers, body);
this.handleWebhookEvent(parsed, res);
});
this.router.addRoute(
"POST",
"/webhooks/custom/:name",
async (req, res, params) => {
const body = await this.readBody(req);
const parsed = CustomWebhookParser.parse(req.headers, body);
this.handleWebhookEvent(parsed, res);
}
);
this.router.addRoute("GET", "/api/v1/personas", (req, res) => {

@@ -689,3 +732,5 @@ res.statusCode = 200;

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: "Unsupported or unparseable webhook event." }));
res.end(
JSON.stringify({ error: "Unsupported or unparseable webhook event." })
);
return;

@@ -751,4 +796,10 @@ }

res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, DELETE"
);
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, X-API-Key"
);
if (req.method === "OPTIONS") {

@@ -780,19 +831,27 @@ res.statusCode = 204;

if (method === "tools/list") {
res.end(JSON.stringify({
result: {
tools: [
{
name: "devdiff_analyze",
description: "Analyzes code changes and returns persona-aware explanation.",
inputSchema: {
type: "object",
properties: {
range: { type: "string", description: "Git revision range" },
persona: { type: "string", description: "AI output persona" }
res.end(
JSON.stringify({
result: {
tools: [
{
name: "devdiff_analyze",
description: "Analyzes code changes and returns persona-aware explanation.",
inputSchema: {
type: "object",
properties: {
range: {
type: "string",
description: "Git revision range"
},
persona: {
type: "string",
description: "AI output persona"
}
}
}
}
}
]
}
}));
]
}
})
);
} else if (method === "tools/call") {

@@ -802,3 +861,6 @@ const args = body.params?.arguments || {};

repoPath: this.config.repoPath,
change_range: args.range ? { from: args.range.split("..")[0], to: args.range.split("..")[1] } : void 0,
change_range: args.range ? {
from: args.range.split("..")[0],
to: args.range.split("..")[1]
} : void 0,
personaId: args.persona || "developer",

@@ -815,12 +877,14 @@ formats: ["markdown"]

]);
res.end(JSON.stringify({
result: {
content: [
{
type: "text",
text: resultContext.outputs?.["markdown"] || "No explanation generated."
}
]
}
}));
res.end(
JSON.stringify({
result: {
content: [
{
type: "text",
text: resultContext.outputs?.["markdown"] || "No explanation generated."
}
]
}
})
);
} catch (err) {

@@ -841,7 +905,9 @@ res.end(JSON.stringify({ error: err.message }));

const body = await this.readBody(req);
res.end(JSON.stringify({
status: "success",
pipeline: body.skill || "devdiff",
processedAt: (/* @__PURE__ */ new Date()).toISOString()
}));
res.end(
JSON.stringify({
status: "success",
pipeline: body.skill || "devdiff",
processedAt: (/* @__PURE__ */ new Date()).toISOString()
})
);
} else {

@@ -860,3 +926,5 @@ res.statusCode = 405;

new Promise((resolve2) => this.mcpServer.listen(mcpPort, resolve2)),
new Promise((resolve2) => this.openclawServer.listen(openclawPort, resolve2)),
new Promise(
(resolve2) => this.openclawServer.listen(openclawPort, resolve2)
),
new Promise((resolve2) => this.grpcServer.listen(grpcPort, resolve2))

@@ -878,3 +946,5 @@ ]);

new Promise((resolve2) => this.mcpServer.close(() => resolve2())),
new Promise((resolve2) => this.openclawServer.close(() => resolve2())),
new Promise(
(resolve2) => this.openclawServer.close(() => resolve2())
),
new Promise((resolve2) => this.grpcServer.close(() => resolve2()))

@@ -1064,6 +1134,6 @@ ]);

const arrows = {
"arrow": "-->",
"open": "---",
"dotted": "-.->",
"thick": "==>"
arrow: "-->",
open: "---",
dotted: "-.->",
thick: "==>"
};

@@ -1080,3 +1150,5 @@ return `${fromId} ${edgeLabel}${arrows[type]} ${toId}`;

if (openBrackets !== closeBrackets) {
errors.push(`Bracket mismatch: ${openBrackets} open, ${closeBrackets} close`);
errors.push(
`Bracket mismatch: ${openBrackets} open, ${closeBrackets} close`
);
}

@@ -1125,4 +1197,8 @@ const quotes = diagram.match(/"/g) || [];

lines.push(` ${parentNode}[${MermaidSanitizer.toLabel(c.summary)}]`);
lines.push(` ${targetNode}[${MermaidSanitizer.toLabel(c.affectedModule)}]`);
lines.push(` ${parentNode} --> |${MermaidSanitizer.toLabel(c.impact)}| ${targetNode}`);
lines.push(
` ${targetNode}[${MermaidSanitizer.toLabel(c.affectedModule)}]`
);
lines.push(
` ${parentNode} --> |${MermaidSanitizer.toLabel(c.impact)}| ${targetNode}`
);
lines.push(` style ${parentNode} fill:${this.getColor(c.type)}`);

@@ -1156,3 +1232,5 @@ });

if (beforeKeys.length > 0 && afterKeys.length > 0) {
lines.push(` ${MermaidSanitizer.toNodeId(`B_${beforeKeys[0]}`)} -.-> |"refactored to"| ${MermaidSanitizer.toNodeId(`A_${afterKeys[0]}`)}`);
lines.push(
` ${MermaidSanitizer.toNodeId(`B_${beforeKeys[0]}`)} -.-> |"refactored to"| ${MermaidSanitizer.toNodeId(`A_${afterKeys[0]}`)}`
);
}

@@ -1167,3 +1245,5 @@ }

const packageLabel = `${d.package}@${d.version}`;
lines.push(` ${packageNode}[${MermaidSanitizer.toLabel(packageLabel)}]`);
lines.push(
` ${packageNode}[${MermaidSanitizer.toLabel(packageLabel)}]`
);
d.dependents.forEach((dep) => {

@@ -1193,3 +1273,5 @@ const depNode = MermaidSanitizer.toNodeId(dep);

const safeName = f.name.replace(/:/g, "_");
lines.push(` ${MermaidSanitizer.toLabel(safeName)}: [${f.frequency}, ${f.complexity}]`);
lines.push(
` ${MermaidSanitizer.toLabel(safeName)}: [${f.frequency}, ${f.complexity}]`
);
});

@@ -1253,3 +1335,8 @@ return this.wrapAndValidate(lines.join("\n"));

let progress = 0;
const stages = ["Parsing diffs", "AST analysis", "AI processing", "Generating outputs"];
const stages = [
"Parsing diffs",
"AST analysis",
"AI processing",
"Generating outputs"
];
for await (const result of generator) {

@@ -1350,3 +1437,6 @@ progress = result.progress || progress;

this.createdAt = Date.now();
this.repository = { path: event.repository.path, branch: event.repository.branch };
this.repository = {
path: event.repository.path,
branch: event.repository.branch
};
this.events = [event];

@@ -1382,3 +1472,6 @@ this.config = { batchWindow: event.config.batchWindow || 3e5 };

queue.enqueue(batch, this.calculatePriority(event));
const totalQueueSize = Array.from(this.repoQueues.values()).reduce((acc, q) => acc + q.size(), 0);
const totalQueueSize = Array.from(this.repoQueues.values()).reduce(
(acc, q) => acc + q.size(),
0
);
if (totalQueueSize > this.config.backpressureThreshold) {

@@ -1432,6 +1525,13 @@ this.emit("backpressure:activate");

async processBatch(batch) {
return new Promise((resolve2) => setTimeout(() => resolve2({ success: true, processedEvents: batch.events.length }), 100));
return new Promise(
(resolve2) => setTimeout(
() => resolve2({ success: true, processedEvents: batch.events.length }),
100
)
);
}
timeout(ms, message) {
return new Promise((_, reject) => setTimeout(() => reject(new Error(message)), ms));
return new Promise(
(_, reject) => setTimeout(() => reject(new Error(message)), ms)
);
}

@@ -1448,5 +1548,10 @@ getJob(id) {

constructor(config) {
console.log(`[BullMQ] Initializing Redis-backed queue on ${config.redis.host}:${config.redis.port}`);
console.log(
`[BullMQ] Initializing Redis-backed queue on ${config.redis.host}:${config.redis.port}`
);
this.init(config).catch((err) => {
console.warn("[BullMQ] Initialization failed, running in fallback mode:", err.message);
console.warn(
"[BullMQ] Initialization failed, running in fallback mode:",
err.message
);
});

@@ -1487,3 +1592,5 @@ }

} catch {
console.warn("[BullMQ] bullmq package not installed. Running in mock/fallback mode.");
console.warn(
"[BullMQ] bullmq package not installed. Running in mock/fallback mode."
);
}

@@ -1685,3 +1792,5 @@ }

if (!match) {
throw new Error("Invalid SKILL.md structure: Frontmatter separators (---) missing.");
throw new Error(
"Invalid SKILL.md structure: Frontmatter separators (---) missing."
);
}

@@ -1692,3 +1801,5 @@ const frontmatterRaw = match[1];

if (!parsed.name || !parsed.version) {
throw new Error("SKILL.md frontmatter must contain 'name' and 'version'.");
throw new Error(
"SKILL.md frontmatter must contain 'name' and 'version'."
);
}

@@ -1715,2 +1826,56 @@ return {

};
// src/outputs/formats.ts
var OUTPUT_FORMATS = {
markdown: {
name: "Markdown",
extension: ".md",
mimeType: "text/markdown"
},
mermaid: {
name: "Mermaid Diagram",
extension: ".mmd",
mimeType: "text/plain",
sanitize: true
// Strict ID sanitization
},
json: {
name: "JSON",
extension: ".json",
mimeType: "application/json"
},
slack: {
name: "Slack Message",
channel: true,
streaming: true
// Progressive updates
},
discord: {
name: "Discord Message",
channel: true,
streaming: true
},
teams: {
name: "Microsoft Teams",
channel: true
},
email: {
name: "Email",
smtp: true
},
notion: {
name: "Notion Page",
api: true,
append: true
},
confluence: {
name: "Confluence Page",
api: true
},
obsidian: {
name: "Obsidian Vault",
extension: ".md",
vault: true
}
};
export {

@@ -1741,2 +1906,3 @@ AIProcessor,

MermaidSanitizer,
OUTPUT_FORMATS,
PersonaProcessor,

@@ -1743,0 +1909,0 @@ PriorityQueue,

{
"name": "@eldrex/gateway",
"version": "1.0.0",
"version": "1.0.2",
"description": "Standardized automation hub and protocol gateway for DevDiff",

@@ -24,4 +24,4 @@ "type": "module",

"zod": "^3.23.0",
"@eldrex/core": "1.0.0",
"@eldrex/personas": "1.0.0"
"@eldrex/core": "1.0.2",
"@eldrex/personas": "1.0.2"
},

@@ -28,0 +28,0 @@ "devDependencies": {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display