@browserstack/mcp-server 1.5.0-beta.21 → 1.5.0-beta.23
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/README.md +32 -48
- package/capability/loadtesting.capability-index.json +1876 -0
- package/capability/tm.capability-index.json +50104 -0
- package/dist/config.d.ts +1 -4
- package/dist/config.js +2 -23
- package/dist/index.d.ts +1 -2
- package/dist/index.js +3 -7
- package/dist/lib/constants.d.ts +0 -3
- package/dist/lib/constants.js +0 -3
- package/dist/lib/instrumentation.d.ts +2 -14
- package/dist/lib/instrumentation.js +29 -104
- package/dist/lib/upload-validator.d.ts +2 -3
- package/dist/lib/upload-validator.js +15 -18
- package/dist/lib/utils.js +3 -10
- package/dist/lib/version-resolver.d.ts +5 -0
- package/dist/lib/version-resolver.js +2 -8
- package/dist/logger.js +10 -1
- package/dist/server-factory.js +6 -10
- package/dist/tools/accessibility.js +5 -9
- package/dist/tools/accessiblity-utils/accessibility-rag.js +1 -3
- package/dist/tools/appautomate-utils/native-execution/constants.js +2 -4
- package/dist/tools/appautomate.js +1 -3
- package/dist/tools/applive.js +1 -1
- package/dist/tools/automate.d.ts +0 -7
- package/dist/tools/automate.js +1 -104
- package/dist/tools/bstack-sdk.js +2 -2
- package/dist/tools/build-insights.js +2 -41
- package/dist/tools/capability-registry/bind.d.ts +29 -0
- package/dist/tools/capability-registry/bind.js +329 -0
- package/dist/tools/capability-registry/config.d.ts +62 -0
- package/dist/tools/capability-registry/config.js +218 -0
- package/dist/tools/capability-registry/discovery.d.ts +44 -0
- package/dist/tools/capability-registry/discovery.js +99 -0
- package/dist/tools/capability-registry/egress.d.ts +44 -0
- package/dist/tools/capability-registry/egress.js +174 -0
- package/dist/tools/capability-registry/index-loader.d.ts +133 -0
- package/dist/tools/capability-registry/index-loader.js +404 -0
- package/dist/tools/capability-registry/register.d.ts +48 -0
- package/dist/tools/capability-registry/register.js +604 -0
- package/dist/tools/capability-registry/resolve.d.ts +38 -0
- package/dist/tools/capability-registry/resolve.js +45 -0
- package/dist/tools/capability-registry/search.d.ts +170 -0
- package/dist/tools/capability-registry/search.js +709 -0
- package/dist/tools/capability-registry/types.d.ts +282 -0
- package/dist/tools/capability-registry/types.js +33 -0
- package/dist/tools/failurelogs-utils/app-automate.js +3 -4
- package/dist/tools/failurelogs-utils/automate.js +4 -5
- package/dist/tools/get-failure-logs.js +11 -30
- package/dist/tools/observability.js +1 -3
- package/dist/tools/percy-sdk.js +9 -9
- package/dist/tools/rca-agent-utils/format-rca.js +4 -5
- package/dist/tools/rca-agent-utils/get-failed-test-id.js +0 -12
- package/dist/tools/rca-agent-utils/types.d.ts +0 -1
- package/dist/tools/rca-agent.js +2 -5
- package/dist/tools/review-agent.js +1 -2
- package/dist/tools/sdk-utils/common/constants.d.ts +1 -1
- package/dist/tools/sdk-utils/common/constants.js +1 -2
- package/dist/tools/selfheal.js +3 -6
- package/dist/tools/testmanagement-utils/TCG-utils/api.js +7 -26
- package/dist/tools/testmanagement-utils/TCG-utils/config.d.ts +0 -2
- package/dist/tools/testmanagement-utils/TCG-utils/config.js +0 -5
- package/dist/tools/testmanagement-utils/testcase-from-file.js +1 -2
- package/dist/tools/testmanagement-utils/upload-file.js +2 -16
- package/dist/tools/testmanagement.js +17 -39
- package/package.json +11 -5
- package/dist/lib/node-version-notice.d.ts +0 -1
- package/dist/lib/node-version-notice.js +0 -9
- package/dist/lib/tool-latency.d.ts +0 -4
- package/dist/lib/tool-latency.js +0 -16
- package/dist/lib/untrusted-content.d.ts +0 -15
- package/dist/lib/untrusted-content.js +0 -24
- package/dist/tools/ask-browserstack/central-oauth.d.ts +0 -120
- package/dist/tools/ask-browserstack/central-oauth.js +0 -277
- package/dist/tools/ask-browserstack/config.d.ts +0 -102
- package/dist/tools/ask-browserstack/config.js +0 -140
- package/dist/tools/ask-browserstack/egress.d.ts +0 -34
- package/dist/tools/ask-browserstack/egress.js +0 -31
- package/dist/tools/ask-browserstack/register.d.ts +0 -61
- package/dist/tools/ask-browserstack/register.js +0 -416
- package/dist/tools/ask-browserstack/relay.d.ts +0 -201
- package/dist/tools/ask-browserstack/relay.js +0 -577
- package/dist/tools/ask-browserstack/stream.d.ts +0 -116
- package/dist/tools/ask-browserstack/stream.js +0 -236
- package/dist/tools/ask-browserstack/types.d.ts +0 -196
- package/dist/tools/ask-browserstack/types.js +0 -14
- package/dist/tools/automate-utils/list-session-ids.d.ts +0 -28
- package/dist/tools/automate-utils/list-session-ids.js +0 -87
- package/dist/tools/automate-utils/resolve-hashed-build-id.d.ts +0 -30
- package/dist/tools/automate-utils/resolve-hashed-build-id.js +0 -124
- package/dist/tools/failurelogs-utils/resolve-app-build-id.d.ts +0 -2
- package/dist/tools/failurelogs-utils/resolve-app-build-id.js +0 -5
- package/dist/tools/failurelogs-utils/video.d.ts +0 -3
- package/dist/tools/failurelogs-utils/video.js +0 -25
- package/dist/tools/tool-handoff.d.ts +0 -66
- package/dist/tools/tool-handoff.js +0 -78
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoke one endpoint and hand back what the product said.
|
|
3
|
+
*
|
|
4
|
+
* NO POST-PROCESSING, BY DECISION. There used to be row extraction by shape, a `returns`
|
|
5
|
+
* allowlist, a scalars-only filter for undeclared schemas, item counting, ordering, trimming,
|
|
6
|
+
* and guards that reported an empty projection as a registration defect. Every one of them
|
|
7
|
+
* was a place where we could be wrong ABOUT a correct answer — and each time we were, the
|
|
8
|
+
* caller saw a confident empty result rather than an error. The product's response is the
|
|
9
|
+
* answer; this module's job is to get it and return it.
|
|
10
|
+
*
|
|
11
|
+
* ONE REQUEST, ONE RESPONSE. Paging is therefore the caller's, which is why `p` and the
|
|
12
|
+
* page-size parameter are published for paginated endpoints (see `project.py::_is_public`).
|
|
13
|
+
* Hiding them made sense only while this module walked the pages itself.
|
|
14
|
+
*/
|
|
15
|
+
import { bind } from "./bind.js";
|
|
16
|
+
import { authHeaders } from "./egress.js";
|
|
17
|
+
import { InvocationError } from "./index-loader.js";
|
|
18
|
+
function hasNextPage(body) {
|
|
19
|
+
if (typeof body !== "object" || body === null || Array.isArray(body))
|
|
20
|
+
return false;
|
|
21
|
+
const info = body.info;
|
|
22
|
+
if (typeof info !== "object" || info === null)
|
|
23
|
+
return false;
|
|
24
|
+
const next = info.next;
|
|
25
|
+
return next !== null && next !== undefined && next !== false;
|
|
26
|
+
}
|
|
27
|
+
export async function invoke(capability, args, baseUrl, credentials, transport, auth) {
|
|
28
|
+
if (!baseUrl)
|
|
29
|
+
throw new InvocationError("no base URL is configured for that product");
|
|
30
|
+
const bound = bind(capability, args);
|
|
31
|
+
const headers = authHeaders(credentials, auth);
|
|
32
|
+
const response = await transport(capability.method, `${baseUrl.replace(/\/$/, "")}${bound.path}`, headers, bound.query, bound.body);
|
|
33
|
+
const ok = response.status >= 200 && response.status < 300;
|
|
34
|
+
return {
|
|
35
|
+
ok,
|
|
36
|
+
completed: ok && !hasNextPage(response.body),
|
|
37
|
+
http_response: {
|
|
38
|
+
status: response.status,
|
|
39
|
+
body: response.body,
|
|
40
|
+
...(response.status === 0
|
|
41
|
+
? { error: response.error || "the product could not be reached" }
|
|
42
|
+
: {}),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ranking capabilities against a plain-language query.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the Python `discover._score`, including the two properties that were each
|
|
5
|
+
* fixed after a live mis-ranking:
|
|
6
|
+
*
|
|
7
|
+
* * PENALTIES REORDER, THEY DO NOT EXCLUDE. `matched` is the pre-penalty term score and is
|
|
8
|
+
* what decides inclusion; `ranked` carries the preferences. Conflating them dropped 40
|
|
9
|
+
* legitimate matches outright, because a cardinality penalty took an otherwise-valid
|
|
10
|
+
* score to zero and the caller saw "no such capability".
|
|
11
|
+
* * CARDINALITY. A "list" query answered by a single-record getter sends the caller to a
|
|
12
|
+
* capability needing an id it cannot possibly have yet.
|
|
13
|
+
*/
|
|
14
|
+
import { Capability, Mode, ProductIndex } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Query/haystack terms. Verbs are deliberately NOT stopwords — they carry the intent.
|
|
17
|
+
*
|
|
18
|
+
* camelCase is split before lowercasing, so `testRunId`, `test_run_id` and `test run id`
|
|
19
|
+
* all tokenize alike.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Is this the browse wildcard rather than a search?
|
|
23
|
+
*
|
|
24
|
+
* Accepts `*` and `all` — both are what a caller reaches for when the intent is "show me
|
|
25
|
+
* everything", and treating only one of them as the wildcard means the other silently
|
|
26
|
+
* becomes a bad search. Whitespace is tolerated so a pasted value still works.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isBrowseQuery(query?: string): boolean;
|
|
29
|
+
export declare function terms(text: string | undefined): string[];
|
|
30
|
+
/**
|
|
31
|
+
* A term plus its naive singular variants.
|
|
32
|
+
*
|
|
33
|
+
* QUERY SIDE ONLY, which is what makes this cheap and safe. Matching is one-directional
|
|
34
|
+
* substring containment, so indexed `attachments` already contains a query of `attachment`;
|
|
35
|
+
* only the reverse — a plural query against singular text — needs help. Stemming the
|
|
36
|
+
* indexed side too would mean rewriting the product's own vocabulary to guess at English,
|
|
37
|
+
* for no additional match.
|
|
38
|
+
*/
|
|
39
|
+
export declare function termForms(term: string): string[];
|
|
40
|
+
/**
|
|
41
|
+
* ONE canonical spelling of a word, so two spellings of a noun cannot look like two terms.
|
|
42
|
+
*
|
|
43
|
+
* `termForms` is deliberately generous — it offers every candidate and lets substring
|
|
44
|
+
* containment sort them out. Canonicalising needs the opposite: exactly one answer, and
|
|
45
|
+
* the right one. Taking the SHORTEST candidate is what a first cut did, and it folded
|
|
46
|
+
* `cases` to `cas`, so the vocabulary entry `test case` matched no query containing "test
|
|
47
|
+
* cases" — the phrase it exists for. The ambiguity check then fell through to `test`
|
|
48
|
+
* alone, reaching the right verdict by the wrong route.
|
|
49
|
+
*
|
|
50
|
+
* Strip `es` only after a sibilant, where English actually inserts it (`boxes`,
|
|
51
|
+
* `batches`, `statuses`). Otherwise strip the single `s`, which is right for the `-e`
|
|
52
|
+
* plurals this vocabulary is full of: case, suite, phase, template.
|
|
53
|
+
*/
|
|
54
|
+
export declare function singular(word: string): string;
|
|
55
|
+
export declare function modeHint(query: string | undefined): "" | Mode;
|
|
56
|
+
export declare function wantsCollection(query: string | undefined): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* True when a capability answers with many records rather than one.
|
|
59
|
+
*
|
|
60
|
+
* Pagination is the reliable signal — a paged operation is a listing by construction. The
|
|
61
|
+
* plural terminal path segment is a weaker fallback for unpaged collections. (The Python
|
|
62
|
+
* side used the capability NAME here. tm now publishes one, but its verbs are not
|
|
63
|
+
* consistent — the endpoint that lists folders is `get_root_folders_v1` — so the path's
|
|
64
|
+
* terminal noun remains the better signal.)
|
|
65
|
+
*/
|
|
66
|
+
export declare function isCollection(capability: Capability): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* One ranked match, WITH the product it belongs to.
|
|
69
|
+
*
|
|
70
|
+
* Attribution is not decoration: the response tables are per product, so dereferencing a
|
|
71
|
+
* hit's schemas needs to know whose tables to read. It is also what lets a caller pass
|
|
72
|
+
* `product` to invokeCapability when two products share an endpoint — until now search
|
|
73
|
+
* ranked across products and then threw away the only thing that could disambiguate them.
|
|
74
|
+
*/
|
|
75
|
+
export interface SearchHit {
|
|
76
|
+
product: string;
|
|
77
|
+
capability: Capability;
|
|
78
|
+
}
|
|
79
|
+
export interface SearchResult {
|
|
80
|
+
hits: SearchHit[];
|
|
81
|
+
truncated: boolean;
|
|
82
|
+
total_matched: number;
|
|
83
|
+
/**
|
|
84
|
+
* Where this page started, and where the next one begins.
|
|
85
|
+
*
|
|
86
|
+
* `truncated` has always said more matched than fit; nothing said how to reach it, so
|
|
87
|
+
* the only way past the first page was to raise `limit` and re-read everything already
|
|
88
|
+
* seen. `next_offset` is absent on the last page, which is what makes "walk until it
|
|
89
|
+
* stops" terminate without the caller comparing counts.
|
|
90
|
+
*/
|
|
91
|
+
offset: number;
|
|
92
|
+
next_offset?: number;
|
|
93
|
+
/** True when the query was the browse wildcard rather than a search. */
|
|
94
|
+
browse?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* The best pre-penalty term score, and whether it is weak enough to doubt.
|
|
97
|
+
*
|
|
98
|
+
* A vocabulary miss does NOT look like a miss from the outside: "make a new bucket for my
|
|
99
|
+
* tests" returns a full page of eight confident hits, exactly like a query that worked,
|
|
100
|
+
* because containment finds *something* for `make`, `new` and `tests`. The only thing that
|
|
101
|
+
* separates them is how little the match is worth.
|
|
102
|
+
*/
|
|
103
|
+
top_matched: number;
|
|
104
|
+
/** `top_matched` as a fraction of a perfect match — the corpus-independent form. */
|
|
105
|
+
coverage: number;
|
|
106
|
+
weak: boolean;
|
|
107
|
+
}
|
|
108
|
+
/** Which products a query could plausibly be about, when more than one could. */
|
|
109
|
+
export interface ProductAmbiguity {
|
|
110
|
+
/** The products that claim the query's words. Empty when the query settles itself. */
|
|
111
|
+
products: string[];
|
|
112
|
+
/** The shared vocabulary that caused it — what to put in front of the user. */
|
|
113
|
+
terms: string[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Products whose OWN vocabulary the query hits, when no word in the query settles it.
|
|
117
|
+
*
|
|
118
|
+
* Requiring `product` made every CALL unambiguous and did nothing about the agent making
|
|
119
|
+
* two of them: "list all projects" was answered by searching tm, then Load Testing, then
|
|
120
|
+
* merging — a question about which product the user meant, answered by guessing both.
|
|
121
|
+
* Tool-description prose asking the agent to check with the user is a suggestion it is
|
|
122
|
+
* free to decline, and declining is cheaper than interrupting someone.
|
|
123
|
+
*
|
|
124
|
+
* WHOLE VOCABULARY ENTRIES, never their constituent words. Splitting them makes almost
|
|
125
|
+
* everything look shared: Load Testing's "load test" and tm's "test case" both yield
|
|
126
|
+
* `test`, which flagged 135 of the 198 eval queries. Matching entries whole flags 27.
|
|
127
|
+
*
|
|
128
|
+
* A UNIQUE TERM SETTLES IT. "create a test case in a folder" contains `folder`, which
|
|
129
|
+
* both products claim, and `test case`, which only tm does — so the query has already
|
|
130
|
+
* answered the question and there is nothing to ask. Only queries whose every recognised
|
|
131
|
+
* word is shared are genuinely undecided.
|
|
132
|
+
*/
|
|
133
|
+
export declare function ambiguousProducts(products: Record<string, ProductIndex>, query: string | undefined): ProductAmbiguity;
|
|
134
|
+
/** One entity's caller-facing vocabulary: what it is called, and what else it is called. */
|
|
135
|
+
export interface VocabularyEntry {
|
|
136
|
+
entity: string;
|
|
137
|
+
description?: string;
|
|
138
|
+
aliases?: string[];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The product's vocabulary, for a caller whose words are not the product's words.
|
|
142
|
+
*
|
|
143
|
+
* THE ONE FAILURE LEXICAL SEARCH CANNOT FIX. "make a new bucket for my tests" wants the
|
|
144
|
+
* folder-create capability, and `bucket` appears nowhere in the index — no scoring change
|
|
145
|
+
* reaches it, because the word is simply absent. What CAN reach it is the caller: it is a
|
|
146
|
+
* language model, and given tm's entity list it maps bucket -> folder without effort. It
|
|
147
|
+
* just cannot guess the list unprompted.
|
|
148
|
+
*
|
|
149
|
+
* Aliases and a one-line `description`; `title` stays dropped as a near-duplicate of
|
|
150
|
+
* `entity` ("Test run" next to `test_run` buys nothing). Aliases alone route but do not
|
|
151
|
+
* DEFINE — `result -> outcome, execution-result, test-result` never says whether that is
|
|
152
|
+
* the per-case verdict inside a run or a run-level rollup — so an agent holding names and
|
|
153
|
+
* aliases has exactly one way to find out, which is describeEntity once per entity. For
|
|
154
|
+
* tm that is 19 calls at ~1.4KB each, ~27KB, to answer what ~1.6KB of description answers
|
|
155
|
+
* here for every entity at once. The `key_facts` remain out: ten times the size, and the
|
|
156
|
+
* caller can ask describeEntity for the one entity it settles on.
|
|
157
|
+
*
|
|
158
|
+
* Its share of the response grew when search became a shortlist: 3.2KB against a 38KB full
|
|
159
|
+
* search was 8%, against a 6.8KB shortlist it is nearly half. The absolute cost did not
|
|
160
|
+
* change and is still under a thousand tokens — far less than one wrong invoke — so this
|
|
161
|
+
* is budgeted in bytes rather than as a fraction of a baseline that now moves.
|
|
162
|
+
*/
|
|
163
|
+
export declare function vocabularyOf(products: Record<string, ProductIndex>, only?: string): Record<string, VocabularyEntry[]>;
|
|
164
|
+
export declare function searchCapabilities(products: Record<string, ProductIndex>, query?: string, options?: {
|
|
165
|
+
entity?: string;
|
|
166
|
+
product?: string;
|
|
167
|
+
mode?: Mode;
|
|
168
|
+
limit?: number;
|
|
169
|
+
offset?: number;
|
|
170
|
+
}): SearchResult;
|