@ateam-ai/mcp 0.4.74 → 0.4.76
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/package.json +1 -1
- package/src/tools.js +77 -26
package/package.json
CHANGED
package/src/tools.js
CHANGED
|
@@ -239,47 +239,75 @@ function _widgetHasRender(r) {
|
|
|
239
239
|
//
|
|
240
240
|
// Detected here rather than left to a person noticing an empty panel, and
|
|
241
241
|
// reported with the repair attached — a signal the reasoning engine can act on.
|
|
242
|
+
// Extract the FULL argument object of each postMessage(...) call by matching
|
|
243
|
+
// braces, so every call is judged on its own text. The previous version took a
|
|
244
|
+
// fixed 400-character window and concatenated all of them: a send object longer
|
|
245
|
+
// than the window was inspected in part, and `source:"adas-plugin"` in one call
|
|
246
|
+
// could make an unrelated postMessage elsewhere on the page be judged as the
|
|
247
|
+
// ADAS protocol. Both were rejected in review, correctly — an approximate
|
|
248
|
+
// boundary is not a structural one.
|
|
249
|
+
function _postMessageObjects(html) {
|
|
250
|
+
const out = [];
|
|
251
|
+
const re = /postMessage\s*\(\s*\{/g;
|
|
252
|
+
let m;
|
|
253
|
+
while ((m = re.exec(html)) !== null) {
|
|
254
|
+
const open = html.indexOf("{", m.index);
|
|
255
|
+
let depth = 0, i = open, inStr = null, esc = false;
|
|
256
|
+
for (; i < html.length; i++) {
|
|
257
|
+
const c = html[i];
|
|
258
|
+
if (inStr) {
|
|
259
|
+
if (esc) { esc = false; continue; }
|
|
260
|
+
if (c === "\\") { esc = true; continue; }
|
|
261
|
+
if (c === inStr) inStr = null;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (c === '"' || c === "'" || c === "`") { inStr = c; continue; }
|
|
265
|
+
if (c === "{") depth++;
|
|
266
|
+
else if (c === "}") { depth--; if (depth === 0) { i++; break; } }
|
|
267
|
+
}
|
|
268
|
+
// Unbalanced (minified truncation, template weirdness) → skip rather than
|
|
269
|
+
// guess. A message we cannot delimit is one we must not judge.
|
|
270
|
+
if (depth === 0) out.push(html.slice(open, i));
|
|
271
|
+
re.lastIndex = Math.max(re.lastIndex, i);
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
|
|
242
276
|
export function _widgetProtocolProblems(html) {
|
|
243
277
|
if (typeof html !== "string" || !html.includes("postMessage")) return [];
|
|
244
278
|
|
|
245
|
-
// STRUCTURE, NOT TOKENS. The first version matched /correlationId/ anywhere in
|
|
246
|
-
// the file, so a correct widget with an unrelated local named correlationId was
|
|
247
|
-
// reported broken — and `fix_with` would then steer an agent into editing
|
|
248
|
-
// working code. Reviewer was right to reject it. Each check below anchors to
|
|
249
|
-
// the actual send or receive shape.
|
|
250
279
|
const problems = [];
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (/type\s*:\s*["']mcp-call["']/.test(
|
|
264
|
-
|
|
280
|
+
const seen = new Set();
|
|
281
|
+
const add = (p) => { if (!seen.has(p)) { seen.add(p); problems.push(p); } };
|
|
282
|
+
|
|
283
|
+
// Judge each host-directed send INDEPENDENTLY. A page may legitimately
|
|
284
|
+
// postMessage to other targets; only objects that identify themselves as the
|
|
285
|
+
// ADAS plugin channel are the protocol.
|
|
286
|
+
for (const obj of _postMessageObjects(html)) {
|
|
287
|
+
if (!/source\s*:\s*["']adas-plugin["']/.test(obj)) continue;
|
|
288
|
+
|
|
289
|
+
if (/type\s*:\s*["']tool\.call["']/.test(obj)) {
|
|
290
|
+
add('sends message.type:"tool.call" — the host has NEVER accepted it, at any version (silent timeout, no error). Send message:{action:"mcp-call",payload:{requestId,connectorId,tool,args}}.');
|
|
291
|
+
} else if (!/action\s*:\s*["']mcp-call["']/.test(obj)) {
|
|
292
|
+
if (/type\s*:\s*["']mcp-call["']/.test(obj)) {
|
|
293
|
+
add('sends message.TYPE:"mcp-call" — the host matches on message.ACTION for sends, so this is ignored. Use message:{action:"mcp-call",payload:{...}}.');
|
|
265
294
|
} else {
|
|
266
|
-
|
|
295
|
+
add('never sends action:"mcp-call" — the host ignores the message entirely.');
|
|
267
296
|
}
|
|
268
297
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
problems.push('sends the request id as correlationId — the host echoes payload.requestId, so responses never match the pending request and every call times out even when the host answered.');
|
|
298
|
+
if (/payload\s*:\s*\{[^}]*correlationId/.test(obj) || /correlationId\s*:\s*correlationId/.test(obj)) {
|
|
299
|
+
add('sends the request id as correlationId — the host echoes payload.requestId, so responses never match the pending request and every call times out even when the host answered.');
|
|
272
300
|
}
|
|
273
301
|
}
|
|
274
302
|
|
|
275
|
-
// RECEIVE side: only
|
|
303
|
+
// RECEIVE side: only reading correlationId OFF THE HOST PAYLOAD counts.
|
|
276
304
|
if (/payload\s*(\?\.|\.)\s*correlationId/.test(html) ||
|
|
277
305
|
/payload\s*&&\s*[\w$.]*payload\.correlationId/.test(html) ||
|
|
278
306
|
/\{\s*correlationId[^}]*\}\s*=\s*[\w$.]*payload/.test(html)) {
|
|
279
|
-
|
|
307
|
+
add('reads payload.correlationId from the host response — the host sends payload.requestId, so the pending request is never matched.');
|
|
280
308
|
}
|
|
281
309
|
if (/type\s*===?\s*["']tool\.response["']/.test(html)) {
|
|
282
|
-
|
|
310
|
+
add('listens for message.type:"tool.response" — the host replies with "mcp-result".');
|
|
283
311
|
}
|
|
284
312
|
|
|
285
313
|
return problems;
|
|
@@ -2213,6 +2241,24 @@ export const tools = [
|
|
|
2213
2241
|
required: ["solution_id"],
|
|
2214
2242
|
},
|
|
2215
2243
|
},
|
|
2244
|
+
{
|
|
2245
|
+
name: "ateam_github_reconcile",
|
|
2246
|
+
core: true,
|
|
2247
|
+
description:
|
|
2248
|
+
"JOIN a diverged dev and main. Use when ateam_github_promote returns PROMOTE_NEEDS_HUMAN or PROMOTE_PRECONDITION_FAILED — i.e. the automatic main→dev back-merge could not resolve itself.\n\n" +
|
|
2249
|
+
"TRY sync_from_main FIRST; this tool calls it internally (a plain merge keeps both sides with no judgement call) and only escalates when git genuinely conflicts.\n\n" +
|
|
2250
|
+
"On conflict it writes a TWO-PARENT merge commit so the histories actually join. That matters: copying one branch's tree onto the other makes the contents match while leaving NO merge base, so the very next promote conflicts again — equal content is not a reconciled history.\n\n" +
|
|
2251
|
+
"Conflicting files are resolved per file, NEWEST WINS, and every decision is reported. Recency is a heuristic, not intent: read the decisions. On a real tenant main held the newer solution.json while dev held the newer widget, so a blanket choice would have reverted one of them.\n\n" +
|
|
2252
|
+
"WHO NEEDS THIS: any tenant whose deploys predate the dev-routing fix carries main-only commits the platform itself wrote, and hits this on its first promote afterwards. Pass dry_run:true to see the decisions before writing anything.",
|
|
2253
|
+
inputSchema: {
|
|
2254
|
+
type: "object",
|
|
2255
|
+
properties: {
|
|
2256
|
+
solution_id: { type: "string", description: "The solution ID" },
|
|
2257
|
+
dry_run: { type: "boolean", description: "Report the per-file decisions without writing the merge commit." },
|
|
2258
|
+
},
|
|
2259
|
+
required: ["solution_id"],
|
|
2260
|
+
},
|
|
2261
|
+
},
|
|
2216
2262
|
{
|
|
2217
2263
|
name: "ateam_github_sync_from_main",
|
|
2218
2264
|
core: true,
|
|
@@ -5384,6 +5430,11 @@ const handlers = {
|
|
|
5384
5430
|
ateam_github_promote: async ({ solution_id, label, dry_run, skip_tag }, sid) =>
|
|
5385
5431
|
post(`/deploy/solutions/${solution_id}/promote`, { label, dry_run, skip_tag }, sid),
|
|
5386
5432
|
|
|
5433
|
+
ateam_github_reconcile: async ({ solution_id, dry_run }, sid) => {
|
|
5434
|
+
if (!solution_id) throw new Error("solution_id required");
|
|
5435
|
+
return await post(`/deploy/solutions/${solution_id}/reconcile`, { dry_run: dry_run === true }, sid);
|
|
5436
|
+
},
|
|
5437
|
+
|
|
5387
5438
|
ateam_github_sync_from_main: async ({ solution_id, dry_run }, sid) =>
|
|
5388
5439
|
post(`/deploy/solutions/${solution_id}/sync-from-main`, { dry_run }, sid),
|
|
5389
5440
|
|