@buoy-gg/mcp 7.0.35 → 7.0.36
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/{chunk-QL2DJGPP.mjs → chunk-QIINQPNK.mjs} +25 -5
- package/dist/cli.js +25 -5
- package/dist/cli.mjs +1 -1
- package/dist/index.js +25 -5
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
|
@@ -614,7 +614,7 @@ async function waitForBroker(url, attempts = 20) {
|
|
|
614
614
|
var delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
615
615
|
|
|
616
616
|
// src/version.ts
|
|
617
|
-
var VERSION = "7.0.
|
|
617
|
+
var VERSION = "7.0.36" ? "7.0.36" : "0.0.0-dev";
|
|
618
618
|
var PACKAGE_NAME = "@buoy-gg/mcp";
|
|
619
619
|
|
|
620
620
|
// src/update/checkForUpdate.ts
|
|
@@ -2745,6 +2745,9 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
2745
2745
|
body: z13.union([z13.string(), z13.record(z13.unknown()), z13.array(z13.unknown())]).optional().describe(
|
|
2746
2746
|
"For kind 'respond': the response body. Pass JSON directly (an object or array) or a raw string; content-type is inferred."
|
|
2747
2747
|
),
|
|
2748
|
+
bodyPatch: z13.record(z13.unknown()).optional().describe(
|
|
2749
|
+
'For `add` with `fromRequestId` (or a rule `id`): fields deep-merged INTO the real captured response \u2014 the way to change one field of a big payload without pasting it back. Send only what changes, e.g. {"name":"test123"}. Ignored when `body` is given.'
|
|
2750
|
+
),
|
|
2748
2751
|
statusText: z13.string().optional().describe(
|
|
2749
2752
|
"For kind 'respond': the status line's text, e.g. 'Service Unavailable'. Cosmetic \u2014 React Native's XMLHttpRequest has no statusText field, so the app never sees it; it only makes the developer's rule list read correctly."
|
|
2750
2753
|
),
|
|
@@ -2796,6 +2799,7 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
2796
2799
|
status: args.status,
|
|
2797
2800
|
statusText: args.statusText,
|
|
2798
2801
|
body: args.body,
|
|
2802
|
+
bodyPatch: args.bodyPatch,
|
|
2799
2803
|
headers: args.headers,
|
|
2800
2804
|
failKind: args.failKind,
|
|
2801
2805
|
delayMs: args.delayMs,
|
|
@@ -4013,13 +4017,21 @@ function registerInteractTools(server, sync) {
|
|
|
4013
4017
|
description: "List the interactive / labeled elements currently on screen \u2014 the app's live accessibility-style tree walked from the React fiber tree. Each row shows the component name, visible text/label, role, testID, a normalized tap point (tap: x,y in 0\u20131), and its #nativeTag. Rows marked with \u2022 are tappable (have an onPress). Use this to see what's on screen and pick something to tap with tap_element \u2014 no screenshot needed. If you already know the sequence you want to drive, `run_flow` does the whole thing (taps, waits, assertions) in one call instead. Re-run after navigating or when the screen changes, since positions move. Requires Buoy Pro.",
|
|
4014
4018
|
inputSchema: {
|
|
4015
4019
|
interactiveOnly: z18.boolean().optional().describe("Only return tappable (onPress) elements. Default false (include labels/text for context)."),
|
|
4020
|
+
includeBuoy: z18.boolean().optional().describe(
|
|
4021
|
+
"Also list Buoy's own overlay \u2014 the dial, tool sheets, Ask Buoy's chat. Default false: the screen described is the app's. Exact testIDs inside Buoy (buoy-\u2026) can still be tapped without this."
|
|
4022
|
+
),
|
|
4016
4023
|
deviceId: deviceIdInput
|
|
4017
4024
|
}
|
|
4018
4025
|
},
|
|
4019
4026
|
async (args) => {
|
|
4020
4027
|
try {
|
|
4021
4028
|
const target = sync.requireProDevice(args.deviceId);
|
|
4022
|
-
const res = await sync.callAction(
|
|
4029
|
+
const res = await sync.callAction(
|
|
4030
|
+
TOOL_ID2,
|
|
4031
|
+
"describeScreen",
|
|
4032
|
+
{ includeBuoy: args.includeBuoy },
|
|
4033
|
+
target
|
|
4034
|
+
);
|
|
4023
4035
|
const all = res?.elements ?? [];
|
|
4024
4036
|
const elements = args.interactiveOnly ? all.filter((e) => e.interactive) : all;
|
|
4025
4037
|
if (elements.length === 0) {
|
|
@@ -4027,7 +4039,8 @@ function registerInteractTools(server, sync) {
|
|
|
4027
4039
|
"No elements found on screen. If the app just navigated, wait a moment and retry; make sure highlight-updates is enabled in the app."
|
|
4028
4040
|
);
|
|
4029
4041
|
}
|
|
4030
|
-
const
|
|
4042
|
+
const hidden = res.hiddenBuoy ? ` Buoy's own overlay (${res.hiddenBuoy} element${res.hiddenBuoy === 1 ? "" : "s"}) is left out \u2014 pass includeBuoy:true to see it.` : "";
|
|
4043
|
+
const header = `Screen ${res.screen.width}\xD7${res.screen.height} \u2014 ${elements.length} element${elements.length === 1 ? "" : "s"} (\u2022 = tappable). Tap with tap_element({ testID | query | nativeTag }).${hidden}`;
|
|
4031
4044
|
return text5(`${header}
|
|
4032
4045
|
|
|
4033
4046
|
${elements.map(formatElement).join("\n")}`);
|
|
@@ -4048,6 +4061,7 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4048
4061
|
text: z18.string().optional().describe("For a text input: the string to set via onChangeText."),
|
|
4049
4062
|
longPress: z18.boolean().optional().describe("Invoke the element's onLongPress instead of onPress. Fails with a clear reason if the element has no onLongPress handler."),
|
|
4050
4063
|
scrollIntoView: z18.boolean().optional().describe("Scroll the target into view first if it's off-screen. Default true."),
|
|
4064
|
+
includeBuoy: z18.boolean().optional().describe("Let a fuzzy `query` match Buoy's own overlay. Default false \u2014 an exact nativeTag/testID always may."),
|
|
4051
4065
|
deviceId: deviceIdInput
|
|
4052
4066
|
}
|
|
4053
4067
|
},
|
|
@@ -4067,7 +4081,8 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4067
4081
|
value: args.value,
|
|
4068
4082
|
text: args.text,
|
|
4069
4083
|
longPress: args.longPress,
|
|
4070
|
-
scrollIntoView: args.scrollIntoView
|
|
4084
|
+
scrollIntoView: args.scrollIntoView,
|
|
4085
|
+
includeBuoy: args.includeBuoy
|
|
4071
4086
|
},
|
|
4072
4087
|
target
|
|
4073
4088
|
);
|
|
@@ -4079,7 +4094,12 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4079
4094
|
const id = m.testID ? ` [testID=${m.testID}]` : m.nativeTag != null ? ` #${m.nativeTag}` : "";
|
|
4080
4095
|
const scrolledNote = res.scrolled ? " (scrolled into view)" : "";
|
|
4081
4096
|
const verb = m.via === "onValueChange" ? `Set "${label}"${id} \u2192 ${JSON.stringify(m.value)}` : m.via === "onChangeText" ? `Typed ${JSON.stringify(m.value)} into "${label}"${id}` : m.via === "onLongPress" ? `Long-pressed "${label}"${id}` : `Tapped "${label}"${id}`;
|
|
4082
|
-
|
|
4097
|
+
const fx = res.effect;
|
|
4098
|
+
const effectNote = !fx ? "" : fx.commits > 0 ? ` ${fx.commits} re-render${fx.commits === 1 ? "" : "s"} followed.` : ` No re-render followed within ${fx.observedMs}ms \u2014 the handler ran but the app did not react. The element may sit on a screen beneath the current one, or be inert; do not treat this as done.`;
|
|
4099
|
+
const alsoNote = res.alsoMatched?.length ? `
|
|
4100
|
+
Also matched equally well (the choice was a coin toss \u2014 re-tap by #nativeTag if this was wrong):
|
|
4101
|
+
` + res.alsoMatched.map((c) => `- ${c.name}${c.text ? ` "${c.text}"` : ""}${c.testID ? ` [testID=${c.testID}]` : ""}${c.nativeTag != null ? ` #${c.nativeTag}` : ""}`).join("\n") : "";
|
|
4102
|
+
return text5(`${verb}${scrolledNote}.${effectNote}${alsoNote}${flowTip}`);
|
|
4083
4103
|
}
|
|
4084
4104
|
let msg = res?.reason ?? "Tap failed.";
|
|
4085
4105
|
if (res?.candidates?.length) {
|
package/dist/cli.js
CHANGED
|
@@ -652,7 +652,7 @@ var import_node_os = __toESM(require("os"));
|
|
|
652
652
|
var import_node_path = __toESM(require("path"));
|
|
653
653
|
|
|
654
654
|
// src/version.ts
|
|
655
|
-
var VERSION = "7.0.
|
|
655
|
+
var VERSION = "7.0.36" ? "7.0.36" : "0.0.0-dev";
|
|
656
656
|
var PACKAGE_NAME = "@buoy-gg/mcp";
|
|
657
657
|
|
|
658
658
|
// src/update/checkForUpdate.ts
|
|
@@ -1979,6 +1979,9 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
1979
1979
|
body: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.record(import_zod5.z.unknown()), import_zod5.z.array(import_zod5.z.unknown())]).optional().describe(
|
|
1980
1980
|
"For kind 'respond': the response body. Pass JSON directly (an object or array) or a raw string; content-type is inferred."
|
|
1981
1981
|
),
|
|
1982
|
+
bodyPatch: import_zod5.z.record(import_zod5.z.unknown()).optional().describe(
|
|
1983
|
+
'For `add` with `fromRequestId` (or a rule `id`): fields deep-merged INTO the real captured response \u2014 the way to change one field of a big payload without pasting it back. Send only what changes, e.g. {"name":"test123"}. Ignored when `body` is given.'
|
|
1984
|
+
),
|
|
1982
1985
|
statusText: import_zod5.z.string().optional().describe(
|
|
1983
1986
|
"For kind 'respond': the status line's text, e.g. 'Service Unavailable'. Cosmetic \u2014 React Native's XMLHttpRequest has no statusText field, so the app never sees it; it only makes the developer's rule list read correctly."
|
|
1984
1987
|
),
|
|
@@ -2030,6 +2033,7 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
2030
2033
|
status: args.status,
|
|
2031
2034
|
statusText: args.statusText,
|
|
2032
2035
|
body: args.body,
|
|
2036
|
+
bodyPatch: args.bodyPatch,
|
|
2033
2037
|
headers: args.headers,
|
|
2034
2038
|
failKind: args.failKind,
|
|
2035
2039
|
delayMs: args.delayMs,
|
|
@@ -4043,13 +4047,21 @@ function registerInteractTools(server, sync) {
|
|
|
4043
4047
|
description: "List the interactive / labeled elements currently on screen \u2014 the app's live accessibility-style tree walked from the React fiber tree. Each row shows the component name, visible text/label, role, testID, a normalized tap point (tap: x,y in 0\u20131), and its #nativeTag. Rows marked with \u2022 are tappable (have an onPress). Use this to see what's on screen and pick something to tap with tap_element \u2014 no screenshot needed. If you already know the sequence you want to drive, `run_flow` does the whole thing (taps, waits, assertions) in one call instead. Re-run after navigating or when the screen changes, since positions move. Requires Buoy Pro.",
|
|
4044
4048
|
inputSchema: {
|
|
4045
4049
|
interactiveOnly: import_zod18.z.boolean().optional().describe("Only return tappable (onPress) elements. Default false (include labels/text for context)."),
|
|
4050
|
+
includeBuoy: import_zod18.z.boolean().optional().describe(
|
|
4051
|
+
"Also list Buoy's own overlay \u2014 the dial, tool sheets, Ask Buoy's chat. Default false: the screen described is the app's. Exact testIDs inside Buoy (buoy-\u2026) can still be tapped without this."
|
|
4052
|
+
),
|
|
4046
4053
|
deviceId: deviceIdInput
|
|
4047
4054
|
}
|
|
4048
4055
|
},
|
|
4049
4056
|
async (args) => {
|
|
4050
4057
|
try {
|
|
4051
4058
|
const target = sync.requireProDevice(args.deviceId);
|
|
4052
|
-
const res = await sync.callAction(
|
|
4059
|
+
const res = await sync.callAction(
|
|
4060
|
+
TOOL_ID2,
|
|
4061
|
+
"describeScreen",
|
|
4062
|
+
{ includeBuoy: args.includeBuoy },
|
|
4063
|
+
target
|
|
4064
|
+
);
|
|
4053
4065
|
const all = res?.elements ?? [];
|
|
4054
4066
|
const elements = args.interactiveOnly ? all.filter((e) => e.interactive) : all;
|
|
4055
4067
|
if (elements.length === 0) {
|
|
@@ -4057,7 +4069,8 @@ function registerInteractTools(server, sync) {
|
|
|
4057
4069
|
"No elements found on screen. If the app just navigated, wait a moment and retry; make sure highlight-updates is enabled in the app."
|
|
4058
4070
|
);
|
|
4059
4071
|
}
|
|
4060
|
-
const
|
|
4072
|
+
const hidden = res.hiddenBuoy ? ` Buoy's own overlay (${res.hiddenBuoy} element${res.hiddenBuoy === 1 ? "" : "s"}) is left out \u2014 pass includeBuoy:true to see it.` : "";
|
|
4073
|
+
const header = `Screen ${res.screen.width}\xD7${res.screen.height} \u2014 ${elements.length} element${elements.length === 1 ? "" : "s"} (\u2022 = tappable). Tap with tap_element({ testID | query | nativeTag }).${hidden}`;
|
|
4061
4074
|
return text5(`${header}
|
|
4062
4075
|
|
|
4063
4076
|
${elements.map(formatElement).join("\n")}`);
|
|
@@ -4078,6 +4091,7 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4078
4091
|
text: import_zod18.z.string().optional().describe("For a text input: the string to set via onChangeText."),
|
|
4079
4092
|
longPress: import_zod18.z.boolean().optional().describe("Invoke the element's onLongPress instead of onPress. Fails with a clear reason if the element has no onLongPress handler."),
|
|
4080
4093
|
scrollIntoView: import_zod18.z.boolean().optional().describe("Scroll the target into view first if it's off-screen. Default true."),
|
|
4094
|
+
includeBuoy: import_zod18.z.boolean().optional().describe("Let a fuzzy `query` match Buoy's own overlay. Default false \u2014 an exact nativeTag/testID always may."),
|
|
4081
4095
|
deviceId: deviceIdInput
|
|
4082
4096
|
}
|
|
4083
4097
|
},
|
|
@@ -4097,7 +4111,8 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4097
4111
|
value: args.value,
|
|
4098
4112
|
text: args.text,
|
|
4099
4113
|
longPress: args.longPress,
|
|
4100
|
-
scrollIntoView: args.scrollIntoView
|
|
4114
|
+
scrollIntoView: args.scrollIntoView,
|
|
4115
|
+
includeBuoy: args.includeBuoy
|
|
4101
4116
|
},
|
|
4102
4117
|
target
|
|
4103
4118
|
);
|
|
@@ -4109,7 +4124,12 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4109
4124
|
const id = m.testID ? ` [testID=${m.testID}]` : m.nativeTag != null ? ` #${m.nativeTag}` : "";
|
|
4110
4125
|
const scrolledNote = res.scrolled ? " (scrolled into view)" : "";
|
|
4111
4126
|
const verb = m.via === "onValueChange" ? `Set "${label}"${id} \u2192 ${JSON.stringify(m.value)}` : m.via === "onChangeText" ? `Typed ${JSON.stringify(m.value)} into "${label}"${id}` : m.via === "onLongPress" ? `Long-pressed "${label}"${id}` : `Tapped "${label}"${id}`;
|
|
4112
|
-
|
|
4127
|
+
const fx = res.effect;
|
|
4128
|
+
const effectNote = !fx ? "" : fx.commits > 0 ? ` ${fx.commits} re-render${fx.commits === 1 ? "" : "s"} followed.` : ` No re-render followed within ${fx.observedMs}ms \u2014 the handler ran but the app did not react. The element may sit on a screen beneath the current one, or be inert; do not treat this as done.`;
|
|
4129
|
+
const alsoNote = res.alsoMatched?.length ? `
|
|
4130
|
+
Also matched equally well (the choice was a coin toss \u2014 re-tap by #nativeTag if this was wrong):
|
|
4131
|
+
` + res.alsoMatched.map((c) => `- ${c.name}${c.text ? ` "${c.text}"` : ""}${c.testID ? ` [testID=${c.testID}]` : ""}${c.nativeTag != null ? ` #${c.nativeTag}` : ""}`).join("\n") : "";
|
|
4132
|
+
return text5(`${verb}${scrolledNote}.${effectNote}${alsoNote}${flowTip}`);
|
|
4113
4133
|
}
|
|
4114
4134
|
let msg = res?.reason ?? "Tap failed.";
|
|
4115
4135
|
if (res?.candidates?.length) {
|
package/dist/cli.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -687,7 +687,7 @@ var import_node_os = __toESM(require("os"));
|
|
|
687
687
|
var import_node_path = __toESM(require("path"));
|
|
688
688
|
|
|
689
689
|
// src/version.ts
|
|
690
|
-
var VERSION = "7.0.
|
|
690
|
+
var VERSION = "7.0.36" ? "7.0.36" : "0.0.0-dev";
|
|
691
691
|
var PACKAGE_NAME = "@buoy-gg/mcp";
|
|
692
692
|
|
|
693
693
|
// src/update/checkForUpdate.ts
|
|
@@ -2014,6 +2014,9 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
2014
2014
|
body: import_zod5.z.union([import_zod5.z.string(), import_zod5.z.record(import_zod5.z.unknown()), import_zod5.z.array(import_zod5.z.unknown())]).optional().describe(
|
|
2015
2015
|
"For kind 'respond': the response body. Pass JSON directly (an object or array) or a raw string; content-type is inferred."
|
|
2016
2016
|
),
|
|
2017
|
+
bodyPatch: import_zod5.z.record(import_zod5.z.unknown()).optional().describe(
|
|
2018
|
+
'For `add` with `fromRequestId` (or a rule `id`): fields deep-merged INTO the real captured response \u2014 the way to change one field of a big payload without pasting it back. Send only what changes, e.g. {"name":"test123"}. Ignored when `body` is given.'
|
|
2019
|
+
),
|
|
2017
2020
|
statusText: import_zod5.z.string().optional().describe(
|
|
2018
2021
|
"For kind 'respond': the status line's text, e.g. 'Service Unavailable'. Cosmetic \u2014 React Native's XMLHttpRequest has no statusText field, so the app never sees it; it only makes the developer's rule list read correctly."
|
|
2019
2022
|
),
|
|
@@ -2065,6 +2068,7 @@ _\u{1F4CC} pinned \xB7 \u{1F516} saved. Act on one with its id, e.g. network_act
|
|
|
2065
2068
|
status: args.status,
|
|
2066
2069
|
statusText: args.statusText,
|
|
2067
2070
|
body: args.body,
|
|
2071
|
+
bodyPatch: args.bodyPatch,
|
|
2068
2072
|
headers: args.headers,
|
|
2069
2073
|
failKind: args.failKind,
|
|
2070
2074
|
delayMs: args.delayMs,
|
|
@@ -4078,13 +4082,21 @@ function registerInteractTools(server, sync) {
|
|
|
4078
4082
|
description: "List the interactive / labeled elements currently on screen \u2014 the app's live accessibility-style tree walked from the React fiber tree. Each row shows the component name, visible text/label, role, testID, a normalized tap point (tap: x,y in 0\u20131), and its #nativeTag. Rows marked with \u2022 are tappable (have an onPress). Use this to see what's on screen and pick something to tap with tap_element \u2014 no screenshot needed. If you already know the sequence you want to drive, `run_flow` does the whole thing (taps, waits, assertions) in one call instead. Re-run after navigating or when the screen changes, since positions move. Requires Buoy Pro.",
|
|
4079
4083
|
inputSchema: {
|
|
4080
4084
|
interactiveOnly: import_zod18.z.boolean().optional().describe("Only return tappable (onPress) elements. Default false (include labels/text for context)."),
|
|
4085
|
+
includeBuoy: import_zod18.z.boolean().optional().describe(
|
|
4086
|
+
"Also list Buoy's own overlay \u2014 the dial, tool sheets, Ask Buoy's chat. Default false: the screen described is the app's. Exact testIDs inside Buoy (buoy-\u2026) can still be tapped without this."
|
|
4087
|
+
),
|
|
4081
4088
|
deviceId: deviceIdInput
|
|
4082
4089
|
}
|
|
4083
4090
|
},
|
|
4084
4091
|
async (args) => {
|
|
4085
4092
|
try {
|
|
4086
4093
|
const target = sync.requireProDevice(args.deviceId);
|
|
4087
|
-
const res = await sync.callAction(
|
|
4094
|
+
const res = await sync.callAction(
|
|
4095
|
+
TOOL_ID2,
|
|
4096
|
+
"describeScreen",
|
|
4097
|
+
{ includeBuoy: args.includeBuoy },
|
|
4098
|
+
target
|
|
4099
|
+
);
|
|
4088
4100
|
const all = res?.elements ?? [];
|
|
4089
4101
|
const elements = args.interactiveOnly ? all.filter((e) => e.interactive) : all;
|
|
4090
4102
|
if (elements.length === 0) {
|
|
@@ -4092,7 +4104,8 @@ function registerInteractTools(server, sync) {
|
|
|
4092
4104
|
"No elements found on screen. If the app just navigated, wait a moment and retry; make sure highlight-updates is enabled in the app."
|
|
4093
4105
|
);
|
|
4094
4106
|
}
|
|
4095
|
-
const
|
|
4107
|
+
const hidden = res.hiddenBuoy ? ` Buoy's own overlay (${res.hiddenBuoy} element${res.hiddenBuoy === 1 ? "" : "s"}) is left out \u2014 pass includeBuoy:true to see it.` : "";
|
|
4108
|
+
const header = `Screen ${res.screen.width}\xD7${res.screen.height} \u2014 ${elements.length} element${elements.length === 1 ? "" : "s"} (\u2022 = tappable). Tap with tap_element({ testID | query | nativeTag }).${hidden}`;
|
|
4096
4109
|
return text5(`${header}
|
|
4097
4110
|
|
|
4098
4111
|
${elements.map(formatElement).join("\n")}`);
|
|
@@ -4113,6 +4126,7 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4113
4126
|
text: import_zod18.z.string().optional().describe("For a text input: the string to set via onChangeText."),
|
|
4114
4127
|
longPress: import_zod18.z.boolean().optional().describe("Invoke the element's onLongPress instead of onPress. Fails with a clear reason if the element has no onLongPress handler."),
|
|
4115
4128
|
scrollIntoView: import_zod18.z.boolean().optional().describe("Scroll the target into view first if it's off-screen. Default true."),
|
|
4129
|
+
includeBuoy: import_zod18.z.boolean().optional().describe("Let a fuzzy `query` match Buoy's own overlay. Default false \u2014 an exact nativeTag/testID always may."),
|
|
4116
4130
|
deviceId: deviceIdInput
|
|
4117
4131
|
}
|
|
4118
4132
|
},
|
|
@@ -4132,7 +4146,8 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4132
4146
|
value: args.value,
|
|
4133
4147
|
text: args.text,
|
|
4134
4148
|
longPress: args.longPress,
|
|
4135
|
-
scrollIntoView: args.scrollIntoView
|
|
4149
|
+
scrollIntoView: args.scrollIntoView,
|
|
4150
|
+
includeBuoy: args.includeBuoy
|
|
4136
4151
|
},
|
|
4137
4152
|
target
|
|
4138
4153
|
);
|
|
@@ -4144,7 +4159,12 @@ ${elements.map(formatElement).join("\n")}`);
|
|
|
4144
4159
|
const id = m.testID ? ` [testID=${m.testID}]` : m.nativeTag != null ? ` #${m.nativeTag}` : "";
|
|
4145
4160
|
const scrolledNote = res.scrolled ? " (scrolled into view)" : "";
|
|
4146
4161
|
const verb = m.via === "onValueChange" ? `Set "${label}"${id} \u2192 ${JSON.stringify(m.value)}` : m.via === "onChangeText" ? `Typed ${JSON.stringify(m.value)} into "${label}"${id}` : m.via === "onLongPress" ? `Long-pressed "${label}"${id}` : `Tapped "${label}"${id}`;
|
|
4147
|
-
|
|
4162
|
+
const fx = res.effect;
|
|
4163
|
+
const effectNote = !fx ? "" : fx.commits > 0 ? ` ${fx.commits} re-render${fx.commits === 1 ? "" : "s"} followed.` : ` No re-render followed within ${fx.observedMs}ms \u2014 the handler ran but the app did not react. The element may sit on a screen beneath the current one, or be inert; do not treat this as done.`;
|
|
4164
|
+
const alsoNote = res.alsoMatched?.length ? `
|
|
4165
|
+
Also matched equally well (the choice was a coin toss \u2014 re-tap by #nativeTag if this was wrong):
|
|
4166
|
+
` + res.alsoMatched.map((c) => `- ${c.name}${c.text ? ` "${c.text}"` : ""}${c.testID ? ` [testID=${c.testID}]` : ""}${c.nativeTag != null ? ` #${c.nativeTag}` : ""}`).join("\n") : "";
|
|
4167
|
+
return text5(`${verb}${scrolledNote}.${effectNote}${alsoNote}${flowTip}`);
|
|
4148
4168
|
}
|
|
4149
4169
|
let msg = res?.reason ?? "Tap failed.";
|
|
4150
4170
|
if (res?.candidates?.length) {
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/mcp",
|
|
3
3
|
"mcpName": "io.github.buoy-gg/mcp",
|
|
4
|
-
"version": "7.0.
|
|
4
|
+
"version": "7.0.36",
|
|
5
5
|
"description": "MCP server for Buoy devtools — lets any LLM copilot drive Buoy tools (perf-monitor benchmarks, etc.) over the devtool sync protocol",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"socket.io-client": "^4.8.1",
|
|
33
33
|
"zod": "^3.25.0",
|
|
34
34
|
"ws": "^8.18.0",
|
|
35
|
-
"@buoy-gg/sync-broker": "^7.0.
|
|
35
|
+
"@buoy-gg/sync-broker": "^7.0.36"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.0.0",
|