@qase/mcp-server 2.0.3 → 2.1.0
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/CHANGELOG.md +28 -0
- package/build/operations-v2/composites/triage-defect.js +12 -15
- package/build/operations-v2/composites/triage-defect.js.map +1 -1
- package/build/operations-v2/qql/index.js +119 -22
- package/build/operations-v2/qql/index.js.map +1 -1
- package/build/operations-v2/read/project-context.js +115 -25
- package/build/operations-v2/read/project-context.js.map +1 -1
- package/build/utils/output-schemas.d.ts.map +1 -1
- package/build/utils/output-schemas.js +8 -3
- package/build/utils/output-schemas.js.map +1 -1
- package/build/utils/qql-helpers.d.ts.map +1 -1
- package/build/utils/qql-helpers.js +3 -2
- package/build/utils/qql-helpers.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/docs/migration.md +45 -3
- package/package.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.0]
|
|
9
|
+
|
|
10
|
+
### Breaking Changes
|
|
11
|
+
|
|
12
|
+
- **`qase_triage_defect` no longer accepts `run_id` or `failed_result_ids`.** Both were read from the arguments and then ignored — the tool only ever created the defect. `POST /v1/defect/{code}` accepts `title`, `actual_result`, `severity`, `milestone_id`, `attachments`, `custom_field`, and `tags`; there is no field for runs or results, and no endpoint to attach them afterwards. The `runs`/`results` arrays visible on a defect are populated by the test runner when a result is reported as a defect. Reference failing results in `actual_result` instead.
|
|
13
|
+
- **`qase_triage_defect` now requires `actual_result` and `severity`**, which the API has always required. Marking them optional produced requests the API rejects, with nothing in the tool contract to warn about it.
|
|
14
|
+
- **`qql_help` now requires `topic`** and returns that one section. Previously omitting `topic` returned every section at once, which sends the whole reference into the context on each call — and the reference grew substantially in this release. `overview` is now a topic of its own, so the old default is still reachable as `topic: "overview"`. An omitted or unknown topic returns an error listing the valid ones.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **`qase_triage_defect` reported linking it never performed.** The summary printed `Linked results: N` and the structured result carried `linked_results: N`, both derived from the length of the ignored `failed_result_ids` argument — so the tool reported work it had not done. Both are gone, along with `linked_results` from `TriageDefectOutput`. The tool description no longer promises "create defect → link to failing tests" either.
|
|
19
|
+
- **`qase_project_context` no longer truncates collections silently.** Suites, milestones, environments, custom fields, and users were each capped at the first 100 entities with no indication in the response — a project with 2 711 suites reported "Suites: 100" and the consumer had no way to learn it was seeing 3.7% of the data. The result now carries a `coverage` field with `{ total, loaded, truncated }` per collection, and the summary spells out `100 of 2711 ⚠️ truncated` plus how to get the rest. The "Top-level suites (N of M total)" header no longer presents the loaded slice as the project total.
|
|
20
|
+
- `qase_project_context` requested users with no `limit` at all, so the API's own (smaller) default applied. It now asks for a full page like every other collection.
|
|
21
|
+
- **`qql_search` no longer advertises an invalid QQL query.** The `recentFailures` example filtered failed results with `created >= now("-7d")`, but the `result` entity has no `created` field — the only timestamp it exposes is `ended`. The broken query was surfaced both in the `qql_search` tool description and in `qql_help` output, so models were being taught the error at the schema level. It now reads `ended >= now("-7d")`.
|
|
22
|
+
- `qql_help` claimed that "queries are case-sensitive for field values". Enum values in fact accept either the display label or its slug (`severity = "Blocker"` and `severity = "blocker"` match the same value); only `status` and `type` on the `requirement` entity are case-sensitive. The help text now says so, and additionally documents which date fields each entity exposes and that boolean fields accept both `is true` and `= true`.
|
|
23
|
+
- `qql_help` omitted the `!~` operator and the `startOfWeek` / `endOfWeek` / `startOfMonth` / `endOfMonth` functions.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **`qql_help` now documents aggregation.** QQL supports `SELECT (...)` with `COUNT`/`MIN`/`MAX`/`AVG`/`SUM`/`FIRST`/`LAST`, plus `GROUP BY` and `HAVING`, but the help never mentioned it — so a count that one query can answer was being computed by paging through rows. The parentheses after `SELECT` are mandatory (the query fails without them), which is not guessable, and two response quirks that quietly corrupt reports are now called out: aggregates return enums as numeric IDs (`result.status` 1 = Passed, 2 = Failed, 5 = Skipped, 8 = Invalid; `automation` 0/1/2), and grouping by a string field returns it with a `_title` suffix (`GROUP BY suite` → `suite_title`).
|
|
28
|
+
- **`qql_help` now lists the fields of each entity**, replacing six label-only lines. Field names are not uniform across entities, which is the main source of failing queries, so the traps are stated explicitly: `case.suite` is a title but `result.suite` is a numeric ID; `result` has no run-ID field (`run` matches the run title, so results cannot be tied to a run ID in QQL); `result` has no `environment`; `requirement` has no link to cases; and `case.suiteTree` (a suite plus all descendants) is documented for the first time.
|
|
29
|
+
- **`qql_help` gained an `enumValues` topic** covering the valid values per field, including two that fail when guessed: `priority` has no `"critical"` (that is a `severity`), and `run.status` is `In Progress`/`Passed`/`Failed`/`Aborted` — `"active"` is not a status. `result.status` has no `Untested`.
|
|
30
|
+
- **`qase_project_context` accepts `full: true`** to page through every collection instead of fetching only the first 100 of each. Full and partial responses are cached under separate keys, and pagination stops early if a page comes back empty rather than looping.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- `qql_search` accepts queries up to 2 000 characters, matching what the REST endpoint allows. The previous 1 000-character cap halved how many IDs fit in an `in (...)` clause — roughly 80 instead of 170 — doubling the round-trips needed for any set-based analysis.
|
|
35
|
+
|
|
8
36
|
## [2.0.3]
|
|
9
37
|
|
|
10
38
|
### Changed
|
|
@@ -2,36 +2,32 @@ import { z } from 'zod';
|
|
|
2
2
|
import { getApiClient } from '../../client/index.js';
|
|
3
3
|
import { toolRegistry, CreateAnnotation } from '../../utils/registry.js';
|
|
4
4
|
import { toResultAsync, createToolError } from '../../utils/errors.js';
|
|
5
|
-
import { ProjectCodeSchema
|
|
5
|
+
import { ProjectCodeSchema } from '../../utils/validation.js';
|
|
6
6
|
import { TriageDefectOutput } from '../../utils/output-schemas.js';
|
|
7
7
|
import { richResult, summaryBlock, dataBlock } from '../../utils/rich-response.js';
|
|
8
8
|
const Schema = z.object({
|
|
9
9
|
code: ProjectCodeSchema,
|
|
10
10
|
title: z.string().min(1).max(255).describe('Defect title'),
|
|
11
|
+
// title, actual_result, and severity are all required by POST /v1/defect/{code} —
|
|
12
|
+
// marking them optional here only produced requests the API rejects.
|
|
11
13
|
severity: z
|
|
12
14
|
.enum(['undefined', 'blocker', 'critical', 'major', 'normal', 'minor', 'trivial'])
|
|
13
|
-
.
|
|
14
|
-
actual_result: z.string().
|
|
15
|
+
.describe('Required by the API'),
|
|
16
|
+
actual_result: z.string().describe('Observed behavior. Required by the API'),
|
|
15
17
|
description: z.string().optional(),
|
|
16
|
-
run_id: IdSchema.optional().describe('Run containing the failed results'),
|
|
17
|
-
failed_result_ids: z
|
|
18
|
-
.array(z.string())
|
|
19
|
-
.optional()
|
|
20
|
-
.describe('Result hashes to link to this defect (from the run)'),
|
|
21
18
|
tags: z.array(z.string()).optional(),
|
|
22
19
|
attachments: z.array(z.string()).optional(),
|
|
23
20
|
custom_field: z.record(z.any()).optional(),
|
|
24
21
|
});
|
|
25
22
|
async function handler(args) {
|
|
26
23
|
const client = getApiClient();
|
|
27
|
-
const { code,
|
|
24
|
+
const { code, ...defectData } = args;
|
|
28
25
|
// Create defect
|
|
29
26
|
const defectRes = await toResultAsync(client.defects.createDefect(code, defectData));
|
|
30
27
|
const defect = defectRes.match((r) => r.data.result, (e) => {
|
|
31
28
|
throw createToolError(e, 'triage: defect creation failed');
|
|
32
29
|
});
|
|
33
30
|
const defectId = defect.id;
|
|
34
|
-
const linkedCount = failed_result_ids?.length ?? 0;
|
|
35
31
|
const severityIcon = {
|
|
36
32
|
blocker: '🔴',
|
|
37
33
|
critical: '🟠',
|
|
@@ -46,19 +42,20 @@ async function handler(args) {
|
|
|
46
42
|
'',
|
|
47
43
|
`- **Defect ID:** ${defectId}`,
|
|
48
44
|
`- **Project:** ${code}`,
|
|
49
|
-
`- **Severity:** ${args.severity
|
|
50
|
-
`- **Linked results:** ${linkedCount}`,
|
|
45
|
+
`- **Severity:** ${args.severity}`,
|
|
51
46
|
];
|
|
52
47
|
if (args.actual_result) {
|
|
53
48
|
lines.push('', '**Actual result:**', `> ${args.actual_result}`);
|
|
54
49
|
}
|
|
55
|
-
const structured = { defect_id: defectId, defect
|
|
50
|
+
const structured = { defect_id: defectId, defect };
|
|
56
51
|
return richResult([summaryBlock(lines.join('\n')), dataBlock(structured)], structured);
|
|
57
52
|
}
|
|
58
53
|
toolRegistry.register({
|
|
59
54
|
name: 'qase_triage_defect',
|
|
60
|
-
description: 'Create a defect from a test failure
|
|
61
|
-
'
|
|
55
|
+
description: 'Create a defect from a test failure. Requires title, actual_result, and severity. ' +
|
|
56
|
+
'Note: the API offers no way to attach existing runs or results to a defect — the ' +
|
|
57
|
+
'runs/results seen on a defect are populated by the test runner when a result is ' +
|
|
58
|
+
'reported as a defect. Reference failing results in actual_result instead.',
|
|
62
59
|
schema: Schema,
|
|
63
60
|
handler,
|
|
64
61
|
annotations: CreateAnnotation,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-defect.js","sourceRoot":"","sources":["../../../src/operations-v2/composites/triage-defect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"triage-defect.js","sourceRoot":"","sources":["../../../src/operations-v2/composites/triage-defect.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { getApiClient } from '../../client/index.js';
|
|
9
9
|
import { toolRegistry, ReadAnnotation } from '../../utils/registry.js';
|
|
10
|
-
import { toResultAsync, createToolError } from '../../utils/errors.js';
|
|
10
|
+
import { toResultAsync, createToolError, ToolExecutionError } from '../../utils/errors.js';
|
|
11
11
|
import { QqlExamples } from '../../utils/qql-helpers.js';
|
|
12
12
|
import { QqlSearchOutput } from '../../utils/output-schemas.js';
|
|
13
13
|
import { richResult, summaryBlock, dataBlock, markdownTable } from '../../utils/rich-response.js';
|
|
@@ -21,11 +21,13 @@ const QqlSearchSchema = z.object({
|
|
|
21
21
|
query: z
|
|
22
22
|
.string()
|
|
23
23
|
.min(1)
|
|
24
|
-
|
|
24
|
+
// The REST endpoint accepts 2000 characters; capping at 1000 halved how many
|
|
25
|
+
// IDs fit in an `in (...)` clause and doubled the round-trips for set analysis.
|
|
26
|
+
.max(2000)
|
|
25
27
|
.describe('QQL query expression. Examples:\n' +
|
|
26
28
|
'- entity = "case" and project = "DEMO" and status = "Actual"\n' +
|
|
27
29
|
'- entity = "defect" and severity = "blocker" and status = "open"\n' +
|
|
28
|
-
'- entity = "result" and status = "failed" and
|
|
30
|
+
'- entity = "result" and status = "failed" and ended >= now("-7d")\n' +
|
|
29
31
|
'- entity = "run" and milestone ~ "Sprint 12"\n' +
|
|
30
32
|
'See QQL documentation for full syntax and examples.'),
|
|
31
33
|
limit: z
|
|
@@ -42,14 +44,38 @@ const QqlSearchSchema = z.object({
|
|
|
42
44
|
.optional()
|
|
43
45
|
.describe('Number of results to skip for pagination'),
|
|
44
46
|
});
|
|
47
|
+
/**
|
|
48
|
+
* Help topics. `topic` is required: returning every section at once sends the
|
|
49
|
+
* whole reference into the context on each call, and the sections are large
|
|
50
|
+
* enough that it is worth asking for only the one needed.
|
|
51
|
+
*/
|
|
52
|
+
const HELP_TOPICS = [
|
|
53
|
+
'overview',
|
|
54
|
+
'syntax',
|
|
55
|
+
'entities',
|
|
56
|
+
'operators',
|
|
57
|
+
'functions',
|
|
58
|
+
'examples',
|
|
59
|
+
'aggregation',
|
|
60
|
+
'enumValues',
|
|
61
|
+
];
|
|
45
62
|
/**
|
|
46
63
|
* Schema for QQL help
|
|
47
64
|
*/
|
|
48
65
|
const GetQqlHelpSchema = z.object({
|
|
49
66
|
topic: z
|
|
50
|
-
.enum(
|
|
51
|
-
.
|
|
52
|
-
|
|
67
|
+
.enum(HELP_TOPICS)
|
|
68
|
+
.describe('Which section to return (required — one section per call):\n' +
|
|
69
|
+
'- overview: what QQL is, overall query structure, subscription requirement\n' +
|
|
70
|
+
'- syntax: structure, ordering, custom fields, case-sensitivity, boolean and date fields\n' +
|
|
71
|
+
'- entities: the fields available on each entity — field names are NOT uniform across ' +
|
|
72
|
+
'entities, so read this before writing a query against an unfamiliar one\n' +
|
|
73
|
+
'- operators: comparison, matching, set, null, and logical operators\n' +
|
|
74
|
+
'- functions: currentUser, activeUsers, and the now/startOf*/endOf* date functions\n' +
|
|
75
|
+
'- examples: ready-made queries for common questions\n' +
|
|
76
|
+
'- aggregation: SELECT (COUNT/MIN/MAX/AVG/SUM/FIRST/LAST), GROUP BY, HAVING — use this ' +
|
|
77
|
+
'to count or summarise instead of paging through rows\n' +
|
|
78
|
+
'- enumValues: the valid values for priority, severity, and the per-entity status fields'),
|
|
53
79
|
});
|
|
54
80
|
// ============================================================================
|
|
55
81
|
// HANDLERS
|
|
@@ -101,45 +127,113 @@ async function getQqlHelp(args) {
|
|
|
101
127
|
const help = {
|
|
102
128
|
overview: {
|
|
103
129
|
description: 'QQL (Qase Query Language) allows powerful searches across Qase entities',
|
|
104
|
-
structure: 'entity = "TYPE" and CONDITION [and CONDITION...] [
|
|
130
|
+
structure: 'entity = "TYPE" and CONDITION [and CONDITION...] [SELECT (AGGREGATE...)] ' +
|
|
131
|
+
'[GROUP BY field] [HAVING condition] [ORDER BY field ASC/DESC]',
|
|
105
132
|
entities: ['case', 'defect', 'run', 'result', 'plan', 'requirement'],
|
|
106
133
|
note: 'QQL is only available in Business and Enterprise Qase subscriptions',
|
|
134
|
+
fieldNamesVary: 'Field names are NOT uniform across entities — see the `entities` topic before writing ' +
|
|
135
|
+
'a query. Most common failure: `created` exists on case/defect/plan/requirement but ' +
|
|
136
|
+
'NOT on run (started/ended) or result (ended only).',
|
|
137
|
+
countWithoutPaging: 'To count or aggregate, use SELECT (COUNT(id)) rather than paging through rows — ' +
|
|
138
|
+
'see the `aggregation` topic.',
|
|
107
139
|
},
|
|
108
140
|
syntax: {
|
|
109
141
|
basicStructure: 'entity = "TYPE" and CONDITION [and CONDITION...]',
|
|
110
142
|
ordering: 'ORDER BY field ASC/DESC',
|
|
111
143
|
customFields: 'cf["Field Name"] = value',
|
|
112
|
-
caseNotes: '
|
|
144
|
+
caseNotes: 'Enum values accept either the display label or its slug — severity = "Blocker" and ' +
|
|
145
|
+
'severity = "blocker" match the same value. Exception: on the requirement entity, ' +
|
|
146
|
+
'status and type ARE case-sensitive (type = "User story", not "user-story").',
|
|
113
147
|
stringMatching: '~ operator is case-insensitive substring match',
|
|
148
|
+
booleanFields: 'Boolean fields accept `is true` / `is false` as well as `= true` / `= false`',
|
|
149
|
+
dateFields: 'case, defect, plan, and requirement have created/updated; result has only `ended` ' +
|
|
150
|
+
'(no created/updated); run has started/ended',
|
|
114
151
|
},
|
|
115
152
|
entities: {
|
|
116
|
-
case: 'Test cases
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
case: 'Test cases — entity = "case". Fields: id, title, description, preconditions, ' +
|
|
154
|
+
'postconditions, status, type, behavior, automation, isManual, isToBeAutomated, ' +
|
|
155
|
+
'priority, severity, layer, isMuted, isFlaky, isAiGenerated, suite, suiteTree, ' +
|
|
156
|
+
'milestone, tags, project, author, createdBy, updatedBy, created, updated, deleted, ' +
|
|
157
|
+
'isDeleted, plus custom fields via cf["Name"]. Note: `suite` matches the suite TITLE ' +
|
|
158
|
+
'(a string), and `suiteTree` matches a suite plus all of its descendants.',
|
|
159
|
+
defect: 'Defects/bugs — entity = "defect". Fields: id, title, actual_result, status, severity, ' +
|
|
160
|
+
'resolved, isResolved, milestone, tags, project, author, createdBy, created, updated, ' +
|
|
161
|
+
'deleted, isDeleted, assignee, plus custom fields.',
|
|
162
|
+
run: 'Test runs — entity = "run". Fields: id, title, description, status, plan, environment, ' +
|
|
163
|
+
'milestone, started, ended, isStarted, isEnded, isPublic, isAutotest, isScheduledRun, ' +
|
|
164
|
+
'hash, type, tags, project, author, createdBy, deleted, isDeleted, plus custom fields. ' +
|
|
165
|
+
'Note: no created/updated — use started/ended. status values: "In Progress", "Passed", ' +
|
|
166
|
+
'"Failed", "Aborted" ("active" is not a status).',
|
|
167
|
+
result: 'Test results — entity = "result". Fields: id, caseId, case, run, status, priority, ' +
|
|
168
|
+
'severity, type, layer, suite, tags, comment, timeSpent, ended, isEnded, deleted, ' +
|
|
169
|
+
'isDeleted, milestone, project, author, createdBy, assignee. Note: no created/updated ' +
|
|
170
|
+
'(only `ended`), no title/description, no custom fields, and no environment. Unlike ' +
|
|
171
|
+
'case.suite, result.suite is a numeric suite ID. There is no run-ID field — `run` ' +
|
|
172
|
+
'matches the run TITLE, so results cannot be tied to a specific run ID in QQL; use ' +
|
|
173
|
+
'GET /v1/result/{code}?filters[run]=ID via qase_api for that. status has no ' +
|
|
174
|
+
'"Untested" value.',
|
|
175
|
+
plan: 'Test plans — entity = "plan". Fields: id, title, description, project, created, updated, deleted, isDeleted.',
|
|
176
|
+
requirement: 'Requirements — entity = "requirement". Fields: id, title, description, parent, status, ' +
|
|
177
|
+
'type, project, author, createdBy, created, updated, deleted, isDeleted. Note: no link ' +
|
|
178
|
+
'to cases, and status/type are the only case-SENSITIVE enum values in QQL ' +
|
|
179
|
+
'(type = "User story" matches, "user-story" does not).',
|
|
180
|
+
},
|
|
181
|
+
aggregation: {
|
|
182
|
+
description: 'QQL can aggregate server-side instead of making you page through rows and count them.',
|
|
183
|
+
functions: ['COUNT', 'MIN', 'MAX', 'AVG', 'SUM', 'FIRST', 'LAST'],
|
|
184
|
+
syntax: 'SELECT (aggregate[, aggregate...]) [GROUP BY field] [HAVING condition] — the ' +
|
|
185
|
+
'parentheses after SELECT are MANDATORY; without them the query fails with ' +
|
|
186
|
+
'"Query is invalid".',
|
|
187
|
+
examples: [
|
|
188
|
+
'entity = "result" and project = "DEMO" and status = "failed" SELECT (COUNT(id))',
|
|
189
|
+
'entity = "result" and project = "DEMO" SELECT (COUNT(id)) GROUP BY status',
|
|
190
|
+
'entity = "case" and project = "DEMO" SELECT (COUNT(id)) GROUP BY suite HAVING COUNT(id) > 10',
|
|
191
|
+
'entity = "result" and project = "DEMO" SELECT (AVG(timeSpent), MAX(timeSpent))',
|
|
192
|
+
],
|
|
193
|
+
enumsComeBackAsNumbers: 'In aggregate results, enum fields are returned as their numeric IDs, not labels: ' +
|
|
194
|
+
'result.status 1 = Passed, 2 = Failed, 5 = Skipped, 8 = Invalid; ' +
|
|
195
|
+
'automation 0 = Manual, 1 = To be automated, 2 = Automated. Map them before reporting.',
|
|
196
|
+
groupByAddsTitleSuffix: 'Grouping by a string field returns it with a _title suffix — GROUP BY suite yields ' +
|
|
197
|
+
'a `suite_title` key in the response, not `suite`.',
|
|
122
198
|
},
|
|
123
199
|
operators: {
|
|
124
200
|
comparison: ['=', '!=', '<', '<=', '>', '>='],
|
|
125
|
-
string: ['~', 'is', 'is not'],
|
|
201
|
+
string: ['~', '!~', 'is', 'is not'],
|
|
126
202
|
array: ['in', 'not in'],
|
|
127
203
|
null: ['is empty', 'is not empty'],
|
|
128
204
|
logical: ['and', 'or', 'not'],
|
|
129
205
|
},
|
|
206
|
+
enumValues: {
|
|
207
|
+
priority: '"Not set", "High", "Medium", "Low" — there is NO "critical" priority; ' +
|
|
208
|
+
'priority = "critical" fails. Critical belongs to severity.',
|
|
209
|
+
severity: '"Not set", "Blocker", "Critical", "Major", "Normal", "Minor", "Trivial"',
|
|
210
|
+
caseStatus: '"Actual", "Draft", "Deprecated"',
|
|
211
|
+
caseAutomation: '"Manual" (a.k.a. "Not automated"), "To be automated", "Automated"',
|
|
212
|
+
defectStatus: '"Open", "In progress", "Resolved", "Invalid"',
|
|
213
|
+
runStatus: '"In Progress", "Passed", "Failed", "Aborted"',
|
|
214
|
+
resultStatus: '"passed", "failed", "skipped", "invalid" — there is no "Untested"',
|
|
215
|
+
},
|
|
130
216
|
functions: {
|
|
131
217
|
currentUser: 'currentUser() - Returns current user ID',
|
|
132
218
|
activeUsers: 'activeUsers() - Returns all active user IDs',
|
|
133
|
-
now: 'now("+/-Nd/w/m") - Current timestamp with optional offset (d=days, w=weeks, m=months)',
|
|
134
|
-
startOfDay: 'startOfDay("YYYY-MM-DD") - Start of specified day',
|
|
135
|
-
endOfDay: 'endOfDay("YYYY-MM-DD") - End of specified day',
|
|
219
|
+
now: 'now("+/-Nd/w/m") - Current timestamp with optional offset (d=days, w=weeks, m=months; hours and years are NOT supported)',
|
|
220
|
+
startOfDay: 'startOfDay("YYYY-MM-DD") - Start of specified day (also accepts an offset)',
|
|
221
|
+
endOfDay: 'endOfDay("YYYY-MM-DD") - End of specified day (also accepts an offset)',
|
|
222
|
+
startOfWeek: 'startOfWeek("YYYY-MM-DD") - Start of specified week (also accepts an offset)',
|
|
223
|
+
endOfWeek: 'endOfWeek("YYYY-MM-DD") - End of specified week (also accepts an offset)',
|
|
224
|
+
startOfMonth: 'startOfMonth("YYYY-MM-DD") - Start of specified month (also accepts an offset)',
|
|
225
|
+
endOfMonth: 'endOfMonth("YYYY-MM-DD") - End of specified month (also accepts an offset)',
|
|
136
226
|
},
|
|
137
227
|
examples: QqlExamples,
|
|
138
228
|
};
|
|
139
|
-
|
|
140
|
-
|
|
229
|
+
// Handlers receive raw MCP arguments, so the schema's `required` is not
|
|
230
|
+
// enforced at runtime — reject a missing or unknown topic with the list of
|
|
231
|
+
// valid ones rather than returning undefined content.
|
|
232
|
+
if (!topic || !(topic in help)) {
|
|
233
|
+
throw new ToolExecutionError(`Unknown help topic${topic ? ` "${topic}"` : ''}. ` +
|
|
234
|
+
`Pass one of: ${HELP_TOPICS.join(', ')}.`);
|
|
141
235
|
}
|
|
142
|
-
return help;
|
|
236
|
+
return { topic, content: help[topic] };
|
|
143
237
|
}
|
|
144
238
|
// ============================================================================
|
|
145
239
|
// TOOL REGISTRATION
|
|
@@ -154,7 +248,10 @@ toolRegistry.register({
|
|
|
154
248
|
});
|
|
155
249
|
toolRegistry.register({
|
|
156
250
|
name: 'qql_help',
|
|
157
|
-
description: 'Get
|
|
251
|
+
description: 'Get one section of the Qase Query Language (QQL) reference. `topic` is required — ask for ' +
|
|
252
|
+
'the section you need rather than the whole reference. Start with "entities" when you are ' +
|
|
253
|
+
'unsure which fields an entity has (they differ per entity), "aggregation" to count or ' +
|
|
254
|
+
'summarise without paging, and "enumValues" for valid field values.',
|
|
158
255
|
schema: GetQqlHelpSchema,
|
|
159
256
|
handler: getQqlHelp,
|
|
160
257
|
annotations: ReadAnnotation,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/operations-v2/qql/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/operations-v2/qql/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,44 +7,117 @@ import { richResult, summaryBlock, dataBlock } from '../../utils/rich-response.j
|
|
|
7
7
|
import { ProjectContextOutput } from '../../utils/output-schemas.js';
|
|
8
8
|
import { getCache, buildCacheKey, hashToken } from '../../cache/index.js';
|
|
9
9
|
import { getEffectiveToken } from '../../utils/auth-context.js';
|
|
10
|
+
/** Entities requested per API call. 100 is the largest page the Qase API serves. */
|
|
11
|
+
const PAGE_SIZE = 100;
|
|
12
|
+
/**
|
|
13
|
+
* Hard cap on pages fetched per collection when `full` is set. A project with
|
|
14
|
+
* more entities than this still reports the true `total`, so the truncation
|
|
15
|
+
* stays visible instead of silently capping.
|
|
16
|
+
*/
|
|
17
|
+
const MAX_PAGES = 50;
|
|
10
18
|
const Schema = z.object({
|
|
11
19
|
code: ProjectCodeSchema,
|
|
20
|
+
full: z
|
|
21
|
+
.boolean()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Page through every suite, milestone, environment, custom field, and user instead of ' +
|
|
24
|
+
`fetching only the first ${PAGE_SIZE} of each (default: false). Use this when a ` +
|
|
25
|
+
'collection is reported as truncated and you need the complete set — it costs one API ' +
|
|
26
|
+
'call per 100 entities and can return thousands of items, so prefer the targeted list ' +
|
|
27
|
+
'tools or qql_search when you only need a subset.'),
|
|
12
28
|
});
|
|
29
|
+
function coverageOf(page) {
|
|
30
|
+
const loaded = page?.entities?.length ?? 0;
|
|
31
|
+
// Fall back to `loaded` when the endpoint omits `total`, so we never claim a
|
|
32
|
+
// truncation we cannot substantiate.
|
|
33
|
+
const total = page?.total ?? loaded;
|
|
34
|
+
return { total, loaded, truncated: loaded < total };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fetch the first page of a collection, then keep paging while the API reports
|
|
38
|
+
* more entities than collected. Returns the shape of a single list response with
|
|
39
|
+
* `entities` holding everything fetched.
|
|
40
|
+
*/
|
|
41
|
+
async function fetchAll(fetchPage) {
|
|
42
|
+
const first = await fetchPage(PAGE_SIZE, 0);
|
|
43
|
+
if (!first)
|
|
44
|
+
return null;
|
|
45
|
+
const entities = [...(first.entities ?? [])];
|
|
46
|
+
const total = first.total ?? entities.length;
|
|
47
|
+
for (let page = 1; entities.length < total && page < MAX_PAGES; page++) {
|
|
48
|
+
const next = await fetchPage(PAGE_SIZE, page * PAGE_SIZE);
|
|
49
|
+
const batch = next?.entities ?? [];
|
|
50
|
+
// No progress (empty page or an endpoint ignoring offset) — stop rather than
|
|
51
|
+
// spin until MAX_PAGES.
|
|
52
|
+
if (batch.length === 0)
|
|
53
|
+
break;
|
|
54
|
+
entities.push(...batch);
|
|
55
|
+
}
|
|
56
|
+
return { ...first, entities };
|
|
57
|
+
}
|
|
13
58
|
async function handler(args) {
|
|
14
|
-
const { code } = args;
|
|
59
|
+
const { code, full = false } = args;
|
|
15
60
|
const cache = await getCache();
|
|
16
61
|
const host = process.env.QASE_API_DOMAIN || 'api.qase.io';
|
|
17
62
|
const key = buildCacheKey({
|
|
18
63
|
host,
|
|
19
64
|
tenantId: hashToken(getEffectiveToken()),
|
|
20
65
|
resource: 'project_context',
|
|
21
|
-
|
|
66
|
+
// Keep full and partial responses in separate cache entries — otherwise a
|
|
67
|
+
// cached partial set would be served for full: true, and vice versa.
|
|
68
|
+
scope: full ? `${code}:full` : code,
|
|
22
69
|
});
|
|
23
70
|
const cached = await cache.get(key);
|
|
24
71
|
if (cached)
|
|
25
72
|
return cached;
|
|
26
73
|
const client = getApiClient();
|
|
27
|
-
|
|
28
|
-
toResultAsync(client.projects.getProject(code)),
|
|
29
|
-
toResultAsync(client.suites.getSuites(code, undefined, 100, 0)),
|
|
30
|
-
toResultAsync(client.milestones.getMilestones(code, undefined, 100, 0)),
|
|
31
|
-
toResultAsync(client.environment.getEnvironments(code, undefined, undefined, 100, 0)),
|
|
32
|
-
toResultAsync(client.customFields.getCustomFields(undefined, undefined, 100, 0)),
|
|
33
|
-
toResultAsync(client.users.getUsers()),
|
|
34
|
-
]);
|
|
74
|
+
/** Unwrap one settled API call; a rejected or errored call becomes null. */
|
|
35
75
|
const extract = (settled) => {
|
|
36
76
|
if (settled.status === 'fulfilled') {
|
|
37
77
|
return settled.value.match((r) => r.data.result, () => null);
|
|
38
78
|
}
|
|
39
79
|
return null;
|
|
40
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* Fetch one page of a collection, returning null if the call fails so a single
|
|
83
|
+
* failing collection leaves the rest of the context intact.
|
|
84
|
+
*/
|
|
85
|
+
const page = (fetchPage) => async (limit, offset) => {
|
|
86
|
+
const settled = await Promise.allSettled([toResultAsync(fetchPage(limit, offset))]);
|
|
87
|
+
return extract(settled[0]);
|
|
88
|
+
};
|
|
89
|
+
/** One page by default, every page when `full` is set. */
|
|
90
|
+
const collect = (fetchPage) => {
|
|
91
|
+
const fetch = page(fetchPage);
|
|
92
|
+
return full ? fetchAll(fetch) : fetch(PAGE_SIZE, 0);
|
|
93
|
+
};
|
|
94
|
+
const [projectSettled, suites, milestones, environments, customFields, users] = await Promise.all([
|
|
95
|
+
Promise.allSettled([toResultAsync(client.projects.getProject(code))]).then(([s]) => s),
|
|
96
|
+
collect((limit, offset) => client.suites.getSuites(code, undefined, limit, offset)),
|
|
97
|
+
collect((limit, offset) => client.milestones.getMilestones(code, undefined, limit, offset)),
|
|
98
|
+
collect((limit, offset) => client.environment.getEnvironments(code, undefined, undefined, limit, offset)),
|
|
99
|
+
collect((limit, offset) => client.customFields.getCustomFields(undefined, undefined, limit, offset)),
|
|
100
|
+
// Previously called with no limit at all, so the API's own (smaller)
|
|
101
|
+
// default silently applied.
|
|
102
|
+
collect((limit, offset) => client.users.getUsers(limit, offset)),
|
|
103
|
+
]);
|
|
104
|
+
const coverage = {
|
|
105
|
+
suites: coverageOf(suites),
|
|
106
|
+
milestones: coverageOf(milestones),
|
|
107
|
+
environments: coverageOf(environments),
|
|
108
|
+
custom_fields: coverageOf(customFields),
|
|
109
|
+
users: coverageOf(users),
|
|
110
|
+
};
|
|
41
111
|
const context = {
|
|
42
|
-
project: extract(
|
|
43
|
-
suites
|
|
44
|
-
milestones
|
|
45
|
-
environments
|
|
46
|
-
custom_fields:
|
|
47
|
-
users
|
|
112
|
+
project: extract(projectSettled),
|
|
113
|
+
suites,
|
|
114
|
+
milestones,
|
|
115
|
+
environments,
|
|
116
|
+
custom_fields: customFields,
|
|
117
|
+
users,
|
|
118
|
+
// Machine-readable completeness per collection, so a consumer can tell a
|
|
119
|
+
// partial set from a complete one without counting entities itself.
|
|
120
|
+
coverage,
|
|
48
121
|
};
|
|
49
122
|
const TTL = 5 * 60 * 1000; // 5 minutes
|
|
50
123
|
await cache.set(key, context, TTL);
|
|
@@ -53,17 +126,26 @@ async function handler(args) {
|
|
|
53
126
|
const suitesList = context.suites?.entities ?? [];
|
|
54
127
|
const milestonesList = context.milestones?.entities ?? [];
|
|
55
128
|
const envsList = context.environments?.entities ?? [];
|
|
56
|
-
|
|
57
|
-
const
|
|
129
|
+
/** "100 of 2711 ⚠️ truncated" when partial, plain "42" when complete. */
|
|
130
|
+
const countOf = (c) => c.truncated ? `${c.loaded} of ${c.total} ⚠️ truncated` : `${c.loaded}`;
|
|
58
131
|
const lines = [
|
|
59
132
|
`## Project: ${projectName} (${code})`,
|
|
60
133
|
'',
|
|
61
|
-
`- **Suites:** ${
|
|
62
|
-
`- **Milestones:** ${
|
|
63
|
-
`- **Environments:** ${
|
|
64
|
-
`- **Custom fields:** ${
|
|
65
|
-
`- **Team members:** ${
|
|
134
|
+
`- **Suites:** ${countOf(coverage.suites)}`,
|
|
135
|
+
`- **Milestones:** ${countOf(coverage.milestones)}`,
|
|
136
|
+
`- **Environments:** ${countOf(coverage.environments)}`,
|
|
137
|
+
`- **Custom fields:** ${countOf(coverage.custom_fields)}`,
|
|
138
|
+
`- **Team members:** ${countOf(coverage.users)}`,
|
|
66
139
|
];
|
|
140
|
+
const truncated = Object.entries(coverage)
|
|
141
|
+
.filter(([, c]) => c.truncated)
|
|
142
|
+
.map(([name]) => name);
|
|
143
|
+
if (truncated.length > 0) {
|
|
144
|
+
lines.push('', `⚠️ **Partial data:** ${truncated.join(', ')} exceed ${PAGE_SIZE} entities and are ` +
|
|
145
|
+
'truncated above. Do not treat the lists below as complete. Call ' +
|
|
146
|
+
`\`qase_project_context({ code: "${code}", full: true })\` for the full set, or use ` +
|
|
147
|
+
'the targeted list tools / `qql_search` to query a subset.');
|
|
148
|
+
}
|
|
67
149
|
if (envsList.length > 0) {
|
|
68
150
|
lines.push('', '**Environments:** ' + envsList.map((e) => e.title).join(', '));
|
|
69
151
|
}
|
|
@@ -78,7 +160,12 @@ async function handler(args) {
|
|
|
78
160
|
}
|
|
79
161
|
if (suitesList.length > 0) {
|
|
80
162
|
const topLevel = suitesList.filter((s) => !s.parent_id);
|
|
81
|
-
|
|
163
|
+
// Qualify the denominator as loaded, not total — with a truncated set the
|
|
164
|
+
// suites in hand are only a slice of the project.
|
|
165
|
+
const scope = coverage.suites.truncated
|
|
166
|
+
? `${topLevel.length} of ${suitesList.length} loaded, ${coverage.suites.total} in project`
|
|
167
|
+
: `${topLevel.length} of ${suitesList.length} total`;
|
|
168
|
+
lines.push('', `**Top-level suites** (${scope}):`);
|
|
82
169
|
for (const s of topLevel.slice(0, 10)) {
|
|
83
170
|
lines.push(`- ${s.title}`);
|
|
84
171
|
}
|
|
@@ -93,7 +180,10 @@ toolRegistry.register({
|
|
|
93
180
|
description: 'Get full project context in one call: project details, suites tree, milestones, ' +
|
|
94
181
|
'environments, custom fields, and users. Cached for 5 minutes. Use this as the ' +
|
|
95
182
|
'first call when starting work with a project — it seeds all the metadata the LLM ' +
|
|
96
|
-
|
|
183
|
+
`needs without making 6 separate list calls. Each collection returns its first ${PAGE_SIZE} ` +
|
|
184
|
+
'entities by default; the `coverage` field reports `{ total, loaded, truncated }` per ' +
|
|
185
|
+
'collection, so check it before assuming a list is complete. Pass `full: true` to page ' +
|
|
186
|
+
'through everything.',
|
|
97
187
|
schema: Schema,
|
|
98
188
|
handler,
|
|
99
189
|
annotations: ReadAnnotation,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-context.js","sourceRoot":"","sources":["../../../src/operations-v2/read/project-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"project-context.js","sourceRoot":"","sources":["../../../src/operations-v2/read/project-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,oFAAoF;AACpF,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB;;;;GAIG;AACH,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,CAAC;SACJ,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CACP,sFAAsF;QACpF,2BAA2B,SAAS,6CAA6C;QACjF,uFAAuF;QACvF,uFAAuF;QACvF,kDAAkD,CACrD;CACJ,CAAC,CAAC;AAeH,SAAS,UAAU,CAAC,IAAc;IAChC,MAAM,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;IAC3C,6EAA6E;IAC7E,qCAAqC;IACrC,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,MAAM,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,EAAE,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CACrB,SAA+D;IAE/D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC;IAE7C,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,KAAK,IAAI,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,GAAG,SAAS,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;QACnC,6EAA6E;QAC7E,wBAAwB;QACxB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM;QAC9B,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAA4B;IACjD,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,aAAa,CAAC;IAC1D,MAAM,GAAG,GAAG,aAAa,CAAC;QACxB,IAAI;QACJ,QAAQ,EAAE,SAAS,CAAC,iBAAiB,EAAE,CAAC;QACxC,QAAQ,EAAE,iBAAiB;QAC3B,0EAA0E;QAC1E,qEAAqE;QACrE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI;KACpC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,4EAA4E;IAC5E,MAAM,OAAO,GAAG,CAAI,OAAkC,EAAY,EAAE;QAClE,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnC,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,CACxB,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAW,EAC9B,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF;;;OAGG;IACH,MAAM,IAAI,GACR,CAAC,SAA0D,EAAE,EAAE,CAC/D,KAAK,EAAE,KAAa,EAAE,MAAc,EAAqB,EAAE;QACzD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACpF,OAAO,OAAO,CAAwB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC;IAEJ,0DAA0D;IAC1D,MAAM,OAAO,GAAG,CACd,SAA0D,EACvC,EAAE;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/F;QACE,OAAO,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACtF,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACnF,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3F,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CACxB,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAC9E;QACD,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CACxB,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CACzE;QACD,qEAAqE;QACrE,4BAA4B;QAC5B,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;KACxD,CACX,CAAC;IAEF,MAAM,QAAQ,GAAG;QACf,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC;QAC1B,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC;QAClC,YAAY,EAAE,UAAU,CAAC,YAAY,CAAC;QACtC,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC;QACvC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC;KACzB,CAAC;IAEF,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,OAAO,CAA0B,cAAc,CAAC;QACzD,MAAM;QACN,UAAU;QACV,YAAY;QACZ,aAAa,EAAE,YAAY;QAC3B,KAAK;QACL,yEAAyE;QACzE,oEAAoE;QACpE,QAAQ;KACT,CAAC;IAEF,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;IACvC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAEnC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAc,CAAC;IACvC,MAAM,WAAW,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC;IAC3C,MAAM,UAAU,GAAW,OAAO,CAAC,MAAc,EAAE,QAAQ,IAAI,EAAE,CAAC;IAClE,MAAM,cAAc,GAAW,OAAO,CAAC,UAAkB,EAAE,QAAQ,IAAI,EAAE,CAAC;IAC1E,MAAM,QAAQ,GAAW,OAAO,CAAC,YAAoB,EAAE,QAAQ,IAAI,EAAE,CAAC;IAEtE,yEAAyE;IACzE,MAAM,OAAO,GAAG,CAAC,CAAW,EAAU,EAAE,CACtC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;IAEzE,MAAM,KAAK,GAAG;QACZ,eAAe,WAAW,KAAK,IAAI,GAAG;QACtC,EAAE;QACF,iBAAiB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAC3C,qBAAqB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;QACnD,uBAAuB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;QACvD,wBAAwB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE;QACzD,uBAAuB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;KACjD,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACvC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAEzB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CACR,EAAE,EACF,wBAAwB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,SAAS,oBAAoB;YAClF,kEAAkE;YAClE,mCAAmC,IAAI,8CAA8C;YACrF,2DAA2D,CAC9D,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,oBAAoB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAClC,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,cAAc,CAAC,MAAM,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,cAAc,CAAC,MAAM,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC7D,0EAA0E;QAC1E,kDAAkD;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS;YACrC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,OAAO,UAAU,CAAC,MAAM,YAAY,QAAQ,CAAC,MAAM,CAAC,KAAK,aAAa;YAC1F,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,OAAO,UAAU,CAAC,MAAM,QAAQ,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,yBAAyB,KAAK,IAAI,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,UAAU,CACf,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,EAC3C,OAAkC,CACnC,CAAC;AACJ,CAAC;AAED,YAAY,CAAC,QAAQ,CAAC;IACpB,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,kFAAkF;QAClF,gFAAgF;QAChF,mFAAmF;QACnF,iFAAiF,SAAS,GAAG;QAC7F,uFAAuF;QACvF,wFAAwF;QACxF,qBAAqB;IACvB,MAAM,EAAE,MAAM;IACd,OAAO;IACP,WAAW,EAAE,cAAc;IAC3B,YAAY,EAAE,oBAAoB;CACnC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-schemas.d.ts","sourceRoot":"","sources":["../../src/utils/output-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,eAAO,MAAM,cAAc,EAAE,YAQ5B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,YAQjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"output-schemas.d.ts","sourceRoot":"","sources":["../../src/utils/output-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,eAAO,MAAM,cAAc,EAAE,YAQ5B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,YAQjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,YAOhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,YAO7B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,YAkBlC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,YAO1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,YAkBjC,CAAC"}
|
|
@@ -28,9 +28,8 @@ export const TriageDefectOutput = {
|
|
|
28
28
|
properties: {
|
|
29
29
|
defect_id: { type: 'integer', description: 'Created defect ID' },
|
|
30
30
|
defect: { type: 'object', description: 'Full defect entity' },
|
|
31
|
-
linked_results: { type: 'integer', description: 'Number of linked result hashes' },
|
|
32
31
|
},
|
|
33
|
-
required: ['defect_id'
|
|
32
|
+
required: ['defect_id'],
|
|
34
33
|
};
|
|
35
34
|
export const QqlSearchOutput = {
|
|
36
35
|
type: 'object',
|
|
@@ -49,8 +48,14 @@ export const ProjectContextOutput = {
|
|
|
49
48
|
environments: { type: 'object', description: 'Environments list' },
|
|
50
49
|
custom_fields: { type: 'object', description: 'Custom fields list' },
|
|
51
50
|
users: { type: 'object', description: 'Team members list' },
|
|
51
|
+
coverage: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
description: 'Per-collection completeness: each of suites, milestones, environments, custom_fields, ' +
|
|
54
|
+
'and users maps to { total, loaded, truncated }. When truncated is true the list holds ' +
|
|
55
|
+
'only the first `loaded` of `total` entities — re-call with full: true for the rest.',
|
|
56
|
+
},
|
|
52
57
|
},
|
|
53
|
-
required: ['project', 'suites', 'milestones', 'environments'],
|
|
58
|
+
required: ['project', 'suites', 'milestones', 'environments', 'coverage'],
|
|
54
59
|
};
|
|
55
60
|
export const DeleteOutput = {
|
|
56
61
|
type: 'object',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-schemas.js","sourceRoot":"","sources":["../../src/utils/output-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE;QAC1D,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,iBAAiB,CAAC,EAAE;QAC/E,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,4BAA4B,EAAE;KACjF;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,kBAAkB,CAAC;CACvD,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE;QAC1D,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,kCAAkC,EAAE;QACjF,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;KACxD;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;CACpC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAiB;IAC9C,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE;QAChE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;
|
|
1
|
+
{"version":3,"file":"output-schemas.js","sourceRoot":"","sources":["../../src/utils/output-schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qql-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/qql-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,WAAW,gBAAgB;CAC5B;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAAgB;IAE7B;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI;IAKnC;;OAEG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKlC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IAMtC;;OAEG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK9B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,KAAK,GAAG,MAAc,GAAG,IAAI;IAK/D;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;
|
|
1
|
+
{"version":3,"file":"qql-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/qql-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,WAAW,gBAAgB;CAC5B;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAAgB;IAE7B;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI;IAKnC;;OAEG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKlC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IAMtC;;OAEG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK9B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,KAAK,GAAG,MAAc,GAAG,IAAI;IAK/D;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;kCAGQ,MAAM;kCAIN,MAAM;8BAIV,MAAM;gCAIJ,MAAM;4BAIV,MAAM,UAAU,MAAM;8BAIpB,MAAM;+BAIL,MAAM,aAAa,MAAM;CAErD,CAAC"}
|
|
@@ -67,8 +67,9 @@ export class QqlQueryBuilder {
|
|
|
67
67
|
* Common QQL query examples
|
|
68
68
|
*/
|
|
69
69
|
export const QqlExamples = {
|
|
70
|
-
// Find all failed test results in last 7 days
|
|
71
|
-
|
|
70
|
+
// Find all failed test results in last 7 days.
|
|
71
|
+
// Results have no `created` field — `ended` is the only timestamp to filter on.
|
|
72
|
+
recentFailures: (projectCode) => `entity = "result" and project = "${projectCode}" and status = "failed" and ended >= now("-7d")`,
|
|
72
73
|
// Find all open blocker defects
|
|
73
74
|
blockerDefects: (projectCode) => `entity = "defect" and project = "${projectCode}" and severity = "blocker" and status = "open"`,
|
|
74
75
|
// Find all flaky test cases
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qql-helpers.js","sourceRoot":"","sources":["../../src/utils/qql-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,CAAN,IAAY,SAOX;AAPD,WAAY,SAAS;IACnB,0BAAa,CAAA;IACb,8BAAiB,CAAA;IACjB,wBAAW,CAAA;IACX,8BAAiB,CAAA;IACjB,0BAAa,CAAA;IACb,wCAA2B,CAAA;AAC7B,CAAC,EAPW,SAAS,KAAT,SAAS,QAOpB;AAED;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,KAAK,GAAa,EAAE,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,UAAqB;QAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,GAAG,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,WAAmB;QACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,GAAG,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,YAAsB;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,GAAG,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,KAAa,EAAE,YAA4B,KAAK;QACtD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,
|
|
1
|
+
{"version":3,"file":"qql-helpers.js","sourceRoot":"","sources":["../../src/utils/qql-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,CAAN,IAAY,SAOX;AAPD,WAAY,SAAS;IACnB,0BAAa,CAAA;IACb,8BAAiB,CAAA;IACjB,wBAAW,CAAA;IACX,8BAAiB,CAAA;IACjB,0BAAa,CAAA;IACb,wCAA2B,CAAA;AAC7B,CAAC,EAPW,SAAS,KAAT,SAAS,QAOpB;AAED;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,KAAK,GAAa,EAAE,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,UAAqB;QAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,GAAG,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,WAAmB;QACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,GAAG,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,YAAsB;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,GAAG,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,KAAa,EAAE,YAA4B,KAAK;QACtD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,+CAA+C;IAC/C,gFAAgF;IAChF,cAAc,EAAE,CAAC,WAAmB,EAAE,EAAE,CACtC,oCAAoC,WAAW,iDAAiD;IAElG,gCAAgC;IAChC,cAAc,EAAE,CAAC,WAAmB,EAAE,EAAE,CACtC,oCAAoC,WAAW,gDAAgD;IAEjG,4BAA4B;IAC5B,UAAU,EAAE,CAAC,WAAmB,EAAE,EAAE,CAClC,kCAAkC,WAAW,sBAAsB;IAErE,2CAA2C;IAC3C,YAAY,EAAE,CAAC,WAAmB,EAAE,EAAE,CACpC,kCAAkC,WAAW,0DAA0D;IAEzG,6CAA6C;IAC7C,QAAQ,EAAE,CAAC,WAAmB,EAAE,MAAc,EAAE,EAAE,CAChD,kCAAkC,WAAW,mBAAmB,MAAM,GAAG;IAE3E,6BAA6B;IAC7B,UAAU,EAAE,CAAC,WAAmB,EAAE,EAAE,CAClC,iCAAiC,WAAW,4CAA4C;IAE1F,mCAAmC;IACnC,WAAW,EAAE,CAAC,WAAmB,EAAE,SAAiB,EAAE,EAAE,CACtD,kCAAkC,WAAW,sBAAsB,SAAS,GAAG;CAClF,CAAC"}
|
package/build/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "2.0
|
|
1
|
+
export declare const VERSION = "2.1.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/build/version.js
CHANGED
package/docs/migration.md
CHANGED
|
@@ -1,4 +1,42 @@
|
|
|
1
|
-
# Migration Guide
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
Two migrations are covered here: the v1 → v2 tool rename (the bulk of this document), and the smaller [2.0.x → 2.1.0](#20x--210) change to `qase_triage_defect`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 2.0.x → 2.1.0
|
|
8
|
+
|
|
9
|
+
### `qase_triage_defect` dropped `run_id` and `failed_result_ids`
|
|
10
|
+
|
|
11
|
+
Both arguments were accepted and then ignored — the tool only ever created the defect. It also reported `Linked results: N` in its summary and `linked_results: N` in its structured output, both computed from the length of the ignored `failed_result_ids` array, so it claimed linking work it had not performed.
|
|
12
|
+
|
|
13
|
+
This cannot be fixed by forwarding the arguments: `POST /v1/defect/{code}` accepts only `title`, `actual_result`, `severity`, `milestone_id`, `attachments`, `custom_field`, and `tags`, and the defects API has no endpoint for attaching runs or results afterwards. The `runs`/`results` arrays you see on a defect are populated by the test runner when a result is reported as a defect.
|
|
14
|
+
|
|
15
|
+
**If you passed either argument**, remove it and put the context in `actual_result` instead:
|
|
16
|
+
|
|
17
|
+
```diff
|
|
18
|
+
qase_triage_defect {
|
|
19
|
+
code: "PROJ",
|
|
20
|
+
title: "Checkout fails on empty cart",
|
|
21
|
+
severity: "blocker",
|
|
22
|
+
- actual_result: "HTTP 500",
|
|
23
|
+
- run_id: 7,
|
|
24
|
+
- failed_result_ids: ["a1b2c3", "d4e5f6"]
|
|
25
|
+
+ actual_result: "HTTP 500 — failing results a1b2c3, d4e5f6 in run #7"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**If you read `linked_results`** from the response, drop it — it was never a real count. The response is now `{ defect_id, defect }`.
|
|
30
|
+
|
|
31
|
+
To associate results with a defect for real, report the result as a defect from the test runner (`is_defect` on the result), or link the defect to an external tracker issue with `qase_external_issue_link`.
|
|
32
|
+
|
|
33
|
+
### `qase_triage_defect` now requires `actual_result` and `severity`
|
|
34
|
+
|
|
35
|
+
The API has always required both. They were optional in the tool schema, which meant the tool advertised calls the API rejects. Any call that already succeeded is unaffected.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Migration Guide: v1 → v2
|
|
2
40
|
|
|
3
41
|
> **Breaking change**: v2 replaces all 83 v1 tool names with a consolidated set of 29 task-oriented tools (30 total, including the `qase_discover_tools` discovery tool).
|
|
4
42
|
> Every tool name has changed. Update your prompts, workflows, and any automation that references tool names.
|
|
@@ -15,6 +53,8 @@
|
|
|
15
53
|
| CI reporting | 3–4 manual steps | `qase_ci_report` composite |
|
|
16
54
|
| Response format | Pretty-printed JSON, nulls included | Compact JSON (no indent), nulls stripped |
|
|
17
55
|
|
|
56
|
+
> **Replacing a `list_*` tool with `qase_project_context`?** Each collection in the context response holds only its first 100 entities by default, where the v1 `list_*` tools let you page explicitly. Check the `coverage` field — it reports `{ total, loaded, truncated }` per collection — and pass `full: true` when you need the complete set. On a project with more than 100 suites, milestones, environments, custom fields, or users, treating the default response as complete gives you a partial answer. (Before 2.1.0 the truncation was not reported at all.)
|
|
57
|
+
|
|
18
58
|
---
|
|
19
59
|
|
|
20
60
|
## Tool mapping table
|
|
@@ -237,9 +277,11 @@ Accepts a project code, run title, and an array of test results. Creates the run
|
|
|
237
277
|
|
|
238
278
|
### `qase_triage_defect`
|
|
239
279
|
|
|
240
|
-
|
|
280
|
+
Creates a defect from a test failure description. Requires `title`, `actual_result`, and `severity`.
|
|
281
|
+
|
|
282
|
+
Note: the tool does **not** link the defect to runs or results — the API has no field or endpoint for that (see [2.0.x → 2.1.0](#20x--210) above). Reference the failing results in `actual_result`.
|
|
241
283
|
|
|
242
|
-
Replaces: `create_defect
|
|
284
|
+
Replaces: `create_defect`.
|
|
243
285
|
|
|
244
286
|
### `qase_regression_run`
|
|
245
287
|
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"url": "https://github.com/qase-tms/qase-mcp-server",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "2.0
|
|
11
|
+
"version": "2.1.0",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "@qase/mcp-server",
|
|
16
|
-
"version": "2.0
|
|
16
|
+
"version": "2.1.0",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|