@sweny-ai/core 0.1.78 → 0.1.79
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/verify.js +54 -3
- package/package.json +1 -1
package/dist/verify.js
CHANGED
|
@@ -105,22 +105,73 @@ function succeededTools(toolCalls) {
|
|
|
105
105
|
function calledList(toolCalls) {
|
|
106
106
|
return toolCalls.map((c) => c.tool).join(", ") || "none";
|
|
107
107
|
}
|
|
108
|
+
// Tool aliases: first-party SWEny skill tool names ↔ their MCP-server equivalents.
|
|
109
|
+
//
|
|
110
|
+
// When an external MCP server is wired for the same provider a skill covers
|
|
111
|
+
// (e.g. the Linear HTTP MCP server alongside the `linear` skill), both sets of
|
|
112
|
+
// tools are presented to the agent and the agent may pick either. The calls
|
|
113
|
+
// are functionally equivalent — same backend, same effect — but the names
|
|
114
|
+
// differ, so a verify rule that lists one will fail when the agent picked the
|
|
115
|
+
// other. These aliases let either call satisfy the rule.
|
|
116
|
+
//
|
|
117
|
+
// Only unambiguous MCP tool names are aliased. Names that collide across
|
|
118
|
+
// providers (e.g. `get_issue` exists on both Linear and GitHub MCP servers)
|
|
119
|
+
// are deliberately omitted so a call to one provider cannot spuriously
|
|
120
|
+
// satisfy a rule about the other.
|
|
121
|
+
const TOOL_ALIAS_GROUPS = [
|
|
122
|
+
// Linear (official remote MCP at mcp.linear.app — upsert naming)
|
|
123
|
+
["linear_search_issues", "list_issues"],
|
|
124
|
+
["linear_create_issue", "save_issue"],
|
|
125
|
+
["linear_update_issue", "save_issue"],
|
|
126
|
+
["linear_add_comment", "save_comment"],
|
|
127
|
+
["linear_list_teams", "list_teams"],
|
|
128
|
+
// GitHub (github.com/github/github-mcp-server)
|
|
129
|
+
["github_create_issue", "create_issue"],
|
|
130
|
+
["github_search_issues", "search_issues"],
|
|
131
|
+
["github_add_comment", "add_issue_comment"],
|
|
132
|
+
["github_create_pr", "create_pull_request"],
|
|
133
|
+
];
|
|
134
|
+
const TOOL_ALIASES = (() => {
|
|
135
|
+
const map = new Map();
|
|
136
|
+
for (const group of TOOL_ALIAS_GROUPS) {
|
|
137
|
+
for (const name of group) {
|
|
138
|
+
let set = map.get(name);
|
|
139
|
+
if (!set) {
|
|
140
|
+
set = new Set();
|
|
141
|
+
map.set(name, set);
|
|
142
|
+
}
|
|
143
|
+
for (const other of group)
|
|
144
|
+
set.add(other);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return map;
|
|
148
|
+
})();
|
|
149
|
+
function expandAliases(name) {
|
|
150
|
+
return TOOL_ALIASES.get(name) ?? new Set([name]);
|
|
151
|
+
}
|
|
152
|
+
function anyAliasIn(name, set) {
|
|
153
|
+
for (const alias of expandAliases(name)) {
|
|
154
|
+
if (set.has(alias))
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
108
159
|
export function checkAnyToolCalled(required, toolCalls) {
|
|
109
160
|
const succeeded = succeededTools(toolCalls);
|
|
110
|
-
if (required.some((t) =>
|
|
161
|
+
if (required.some((t) => anyAliasIn(t, succeeded)))
|
|
111
162
|
return null;
|
|
112
163
|
return `any_tool_called: required one of [${required.join(", ")}] to succeed, called: [${calledList(toolCalls)}]`;
|
|
113
164
|
}
|
|
114
165
|
export function checkAllToolsCalled(required, toolCalls) {
|
|
115
166
|
const succeeded = succeededTools(toolCalls);
|
|
116
|
-
const missing = required.filter((t) => !
|
|
167
|
+
const missing = required.filter((t) => !anyAliasIn(t, succeeded));
|
|
117
168
|
if (missing.length === 0)
|
|
118
169
|
return null;
|
|
119
170
|
return `all_tools_called: missing successful calls to [${missing.join(", ")}], called: [${calledList(toolCalls)}]`;
|
|
120
171
|
}
|
|
121
172
|
export function checkNoToolCalled(forbidden, toolCalls) {
|
|
122
173
|
const calledNames = new Set(toolCalls.map((c) => c.tool));
|
|
123
|
-
const violated = forbidden.filter((t) =>
|
|
174
|
+
const violated = forbidden.filter((t) => anyAliasIn(t, calledNames));
|
|
124
175
|
if (violated.length === 0)
|
|
125
176
|
return null;
|
|
126
177
|
return `no_tool_called: forbidden tools were invoked: [${violated.join(", ")}], called: [${calledList(toolCalls)}]`;
|