ralph-hero-mcp-server 2.4.13 → 2.4.14

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.
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Routing rule matching engine.
3
+ *
4
+ * Evaluates routing rules against an issue context (repo, labels, type)
5
+ * and returns matched rules with their actions. Pure function — no I/O,
6
+ * no API calls, fully deterministic.
7
+ *
8
+ * Used by: configure_routing dry_run (#179), Actions routing script (#171).
9
+ */
10
+ // ---------------------------------------------------------------------------
11
+ // Public API
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Evaluate routing rules against an issue context.
15
+ *
16
+ * Rules are evaluated top-to-bottom. Each rule's match criteria use AND
17
+ * logic (all specified criteria must match). Omitted criteria are vacuously
18
+ * true. The `negate` flag inverts the combined result.
19
+ *
20
+ * When `stopOnFirstMatch` is true (default), evaluation stops after the
21
+ * first matching rule. Set to false for fan-out routing (one issue →
22
+ * multiple projects).
23
+ */
24
+ export function evaluateRules(config, issue) {
25
+ const results = [];
26
+ const stopOnFirst = config.stopOnFirstMatch ?? true;
27
+ for (let i = 0; i < config.rules.length; i++) {
28
+ const rule = config.rules[i];
29
+ if (rule.enabled === false)
30
+ continue;
31
+ let matched = matchesRule(rule.match, issue);
32
+ if (rule.match.negate)
33
+ matched = !matched;
34
+ if (matched) {
35
+ results.push({ rule, ruleIndex: i, matched: true, actions: rule.action });
36
+ if (stopOnFirst) {
37
+ return { matchedRules: results, stoppedEarly: true };
38
+ }
39
+ }
40
+ }
41
+ return { matchedRules: results, stoppedEarly: false };
42
+ }
43
+ // ---------------------------------------------------------------------------
44
+ // Private Helpers
45
+ // ---------------------------------------------------------------------------
46
+ function matchesRule(criteria, issue) {
47
+ if (criteria.repo && !matchesRepo(criteria.repo, issue.repo))
48
+ return false;
49
+ if (criteria.labels && !matchesLabels(criteria.labels, issue.labels))
50
+ return false;
51
+ if (criteria.issueType && !matchesIssueType(criteria.issueType, issue.issueType))
52
+ return false;
53
+ return true;
54
+ }
55
+ function matchesRepo(pattern, repo) {
56
+ return matchesGlob(pattern.toLowerCase(), repo.toLowerCase());
57
+ }
58
+ function matchesLabels(criteria, issueLabels) {
59
+ const normalized = issueLabels.map((l) => l.toLowerCase());
60
+ if (criteria.any?.length) {
61
+ const hasAny = criteria.any.some((l) => normalized.includes(l.toLowerCase()));
62
+ if (!hasAny)
63
+ return false;
64
+ }
65
+ if (criteria.all?.length) {
66
+ const hasAll = criteria.all.every((l) => normalized.includes(l.toLowerCase()));
67
+ if (!hasAll)
68
+ return false;
69
+ }
70
+ return true;
71
+ }
72
+ function matchesIssueType(expected, actual) {
73
+ return expected.toLowerCase() === actual.toLowerCase();
74
+ }
75
+ function matchesGlob(pattern, input) {
76
+ const regexStr = pattern
77
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
78
+ .replace(/\*\*/g, "\x00")
79
+ .replace(/\*/g, "[^/]*")
80
+ .replace(/\?/g, "[^/]")
81
+ .replace(/\x00/g, ".*");
82
+ return new RegExp(`^${regexStr}$`).test(input);
83
+ }
84
+ //# sourceMappingURL=routing-engine.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-hero-mcp-server",
3
- "version": "2.4.13",
3
+ "version": "2.4.14",
4
4
  "description": "MCP server for GitHub Projects V2 - Ralph workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",