@provartesting/provardx-cli 1.4.6 → 1.5.0-dev
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 +292 -8
- package/lib/commands/provar/automation/config/validate.js.map +1 -1
- package/lib/commands/provar/automation/project/validate.d.ts +14 -0
- package/lib/commands/provar/automation/project/validate.js +69 -0
- package/lib/commands/provar/automation/project/validate.js.map +1 -0
- package/lib/commands/provar/mcp/start.d.ts +16 -0
- package/lib/commands/provar/mcp/start.js +62 -0
- package/lib/commands/provar/mcp/start.js.map +1 -0
- package/lib/commands/provar/quality-hub/connect.d.ts +5 -0
- package/lib/commands/provar/quality-hub/connect.js +12 -0
- package/lib/commands/provar/quality-hub/connect.js.map +1 -0
- package/lib/commands/provar/quality-hub/display.d.ts +5 -0
- package/lib/commands/provar/quality-hub/display.js +12 -0
- package/lib/commands/provar/quality-hub/display.js.map +1 -0
- package/lib/commands/provar/quality-hub/open.d.ts +5 -0
- package/lib/commands/provar/quality-hub/open.js +12 -0
- package/lib/commands/provar/quality-hub/open.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run/abort.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run/abort.js +12 -0
- package/lib/commands/provar/quality-hub/test/run/abort.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run/report.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run/report.js +12 -0
- package/lib/commands/provar/quality-hub/test/run/report.js.map +1 -0
- package/lib/commands/provar/quality-hub/test/run.d.ts +5 -0
- package/lib/commands/provar/quality-hub/test/run.js +12 -0
- package/lib/commands/provar/quality-hub/test/run.js.map +1 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.d.ts +5 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.js +12 -0
- package/lib/commands/provar/quality-hub/testcase/retrieve.js.map +1 -0
- package/lib/mcp/licensing/algasClient.d.ts +19 -0
- package/lib/mcp/licensing/algasClient.js +144 -0
- package/lib/mcp/licensing/algasClient.js.map +1 -0
- package/lib/mcp/licensing/ideDetection.d.ts +34 -0
- package/lib/mcp/licensing/ideDetection.js +179 -0
- package/lib/mcp/licensing/ideDetection.js.map +1 -0
- package/lib/mcp/licensing/index.d.ts +5 -0
- package/lib/mcp/licensing/index.js +10 -0
- package/lib/mcp/licensing/index.js.map +1 -0
- package/lib/mcp/licensing/licenseCache.d.ts +20 -0
- package/lib/mcp/licensing/licenseCache.js +79 -0
- package/lib/mcp/licensing/licenseCache.js.map +1 -0
- package/lib/mcp/licensing/licenseError.d.ts +4 -0
- package/lib/mcp/licensing/licenseError.js +15 -0
- package/lib/mcp/licensing/licenseError.js.map +1 -0
- package/lib/mcp/licensing/licenseValidator.d.ts +33 -0
- package/lib/mcp/licensing/licenseValidator.js +103 -0
- package/lib/mcp/licensing/licenseValidator.js.map +1 -0
- package/lib/mcp/logging/logger.d.ts +7 -0
- package/lib/mcp/logging/logger.js +22 -0
- package/lib/mcp/logging/logger.js.map +1 -0
- package/lib/mcp/rules/page_object_validation_rules.json +344 -0
- package/lib/mcp/rules/provar_best_practices_rules.json +3192 -0
- package/lib/mcp/schemas/common.d.ts +20 -0
- package/lib/mcp/schemas/common.js +16 -0
- package/lib/mcp/schemas/common.js.map +1 -0
- package/lib/mcp/security/pathPolicy.d.ts +14 -0
- package/lib/mcp/security/pathPolicy.js +38 -0
- package/lib/mcp/security/pathPolicy.js.map +1 -0
- package/lib/mcp/server.d.ts +5 -0
- package/lib/mcp/server.js +59 -0
- package/lib/mcp/server.js.map +1 -0
- package/lib/mcp/tools/antTools.d.ts +21 -0
- package/lib/mcp/tools/antTools.js +602 -0
- package/lib/mcp/tools/antTools.js.map +1 -0
- package/lib/mcp/tools/automationTools.d.ts +14 -0
- package/lib/mcp/tools/automationTools.js +386 -0
- package/lib/mcp/tools/automationTools.js.map +1 -0
- package/lib/mcp/tools/bestPracticesEngine.d.ts +30 -0
- package/lib/mcp/tools/bestPracticesEngine.js +632 -0
- package/lib/mcp/tools/bestPracticesEngine.js.map +1 -0
- package/lib/mcp/tools/defectTools.d.ts +15 -0
- package/lib/mcp/tools/defectTools.js +199 -0
- package/lib/mcp/tools/defectTools.js.map +1 -0
- package/lib/mcp/tools/hierarchyValidate.d.ts +139 -0
- package/lib/mcp/tools/hierarchyValidate.js +540 -0
- package/lib/mcp/tools/hierarchyValidate.js.map +1 -0
- package/lib/mcp/tools/pageObjectGenerate.d.ts +3 -0
- package/lib/mcp/tools/pageObjectGenerate.js +153 -0
- package/lib/mcp/tools/pageObjectGenerate.js.map +1 -0
- package/lib/mcp/tools/pageObjectValidate.d.ts +18 -0
- package/lib/mcp/tools/pageObjectValidate.js +420 -0
- package/lib/mcp/tools/pageObjectValidate.js.map +1 -0
- package/lib/mcp/tools/projectInspect.d.ts +3 -0
- package/lib/mcp/tools/projectInspect.js +694 -0
- package/lib/mcp/tools/projectInspect.js.map +1 -0
- package/lib/mcp/tools/projectValidateFromPath.d.ts +3 -0
- package/lib/mcp/tools/projectValidateFromPath.js +153 -0
- package/lib/mcp/tools/projectValidateFromPath.js.map +1 -0
- package/lib/mcp/tools/propertiesTools.d.ts +7 -0
- package/lib/mcp/tools/propertiesTools.js +314 -0
- package/lib/mcp/tools/propertiesTools.js.map +1 -0
- package/lib/mcp/tools/qualityHubTools.d.ts +8 -0
- package/lib/mcp/tools/qualityHubTools.js +178 -0
- package/lib/mcp/tools/qualityHubTools.js.map +1 -0
- package/lib/mcp/tools/rcaTools.d.ts +4 -0
- package/lib/mcp/tools/rcaTools.js +620 -0
- package/lib/mcp/tools/rcaTools.js.map +1 -0
- package/lib/mcp/tools/sfSpawn.d.ts +28 -0
- package/lib/mcp/tools/sfSpawn.js +50 -0
- package/lib/mcp/tools/sfSpawn.js.map +1 -0
- package/lib/mcp/tools/testCaseGenerate.d.ts +3 -0
- package/lib/mcp/tools/testCaseGenerate.js +221 -0
- package/lib/mcp/tools/testCaseGenerate.js.map +1 -0
- package/lib/mcp/tools/testCaseValidate.d.ts +20 -0
- package/lib/mcp/tools/testCaseValidate.js +227 -0
- package/lib/mcp/tools/testCaseValidate.js.map +1 -0
- package/lib/mcp/tools/testPlanTools.d.ts +6 -0
- package/lib/mcp/tools/testPlanTools.js +311 -0
- package/lib/mcp/tools/testPlanTools.js.map +1 -0
- package/lib/mcp/tools/testPlanValidate.d.ts +2 -0
- package/lib/mcp/tools/testPlanValidate.js +75 -0
- package/lib/mcp/tools/testPlanValidate.js.map +1 -0
- package/lib/mcp/tools/testSuiteValidate.d.ts +2 -0
- package/lib/mcp/tools/testSuiteValidate.js +63 -0
- package/lib/mcp/tools/testSuiteValidate.js.map +1 -0
- package/lib/services/projectValidation.d.ts +119 -0
- package/lib/services/projectValidation.js +678 -0
- package/lib/services/projectValidation.js.map +1 -0
- package/messages/sf.provar.automation.project.validate.md +52 -0
- package/messages/sf.provar.mcp.start.md +74 -0
- package/oclif.manifest.json +1298 -1
- package/package.json +29 -15
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { spawnSync as _spawnSync } from 'node:child_process';
|
|
3
|
+
/**
|
|
4
|
+
* Thin wrapper around spawnSync so tests can stub sfSpawnHelper.spawnSync.
|
|
5
|
+
* ESM named exports are immutable bindings; sinon requires a mutable object property.
|
|
6
|
+
*/
|
|
7
|
+
export declare const sfSpawnHelper: {
|
|
8
|
+
spawnSync: typeof _spawnSync;
|
|
9
|
+
};
|
|
10
|
+
export declare class SfNotFoundError extends Error {
|
|
11
|
+
readonly code = "SF_NOT_FOUND";
|
|
12
|
+
constructor();
|
|
13
|
+
}
|
|
14
|
+
export interface SpawnResult {
|
|
15
|
+
stdout: string;
|
|
16
|
+
stderr: string;
|
|
17
|
+
exitCode: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run `sf <args>` synchronously and return stdout, stderr, and exit code.
|
|
21
|
+
* Throws SfNotFoundError if the `sf` binary is not in PATH.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runSfCommand(args: string[]): SpawnResult;
|
|
24
|
+
/**
|
|
25
|
+
* Escape a value for safe interpolation inside a SOQL single-quoted string literal.
|
|
26
|
+
* Replaces `'` with `\'` to prevent SOQL injection.
|
|
27
|
+
*/
|
|
28
|
+
export declare function soqlEscape(value: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync as _spawnSync } from 'node:child_process';
|
|
8
|
+
/**
|
|
9
|
+
* Thin wrapper around spawnSync so tests can stub sfSpawnHelper.spawnSync.
|
|
10
|
+
* ESM named exports are immutable bindings; sinon requires a mutable object property.
|
|
11
|
+
*/
|
|
12
|
+
export const sfSpawnHelper = {
|
|
13
|
+
spawnSync: _spawnSync,
|
|
14
|
+
};
|
|
15
|
+
// ── Shared error type ─────────────────────────────────────────────────────────
|
|
16
|
+
export class SfNotFoundError extends Error {
|
|
17
|
+
code = 'SF_NOT_FOUND';
|
|
18
|
+
constructor() {
|
|
19
|
+
super('sf CLI not found in PATH. Install Salesforce CLI (`npm install -g @salesforce/cli`) and ensure it is in your PATH.');
|
|
20
|
+
this.name = 'SfNotFoundError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run `sf <args>` synchronously and return stdout, stderr, and exit code.
|
|
25
|
+
* Throws SfNotFoundError if the `sf` binary is not in PATH.
|
|
26
|
+
*/
|
|
27
|
+
export function runSfCommand(args) {
|
|
28
|
+
const result = sfSpawnHelper.spawnSync('sf', args, { encoding: 'utf-8', shell: false });
|
|
29
|
+
if (result.error) {
|
|
30
|
+
const err = result.error;
|
|
31
|
+
if (err.code === 'ENOENT') {
|
|
32
|
+
throw new SfNotFoundError();
|
|
33
|
+
}
|
|
34
|
+
throw result.error;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
stdout: result.stdout ?? '',
|
|
38
|
+
stderr: result.stderr ?? '',
|
|
39
|
+
exitCode: result.status ?? 1,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// ── SOQL safety ───────────────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Escape a value for safe interpolation inside a SOQL single-quoted string literal.
|
|
45
|
+
* Replaces `'` with `\'` to prevent SOQL injection.
|
|
46
|
+
*/
|
|
47
|
+
export function soqlEscape(value) {
|
|
48
|
+
return value.replace(/'/g, "\\'");
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=sfSpawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfSpawn.js","sourceRoot":"","sources":["../../../src/mcp/tools/sfSpawn.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS,EAAE,UAAU;CACtB,CAAC;AAEF,iFAAiF;AAEjF,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxB,IAAI,GAAG,cAAc,CAAC;IACtC;QACE,KAAK,CACH,oHAAoH,CACrH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAUD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAExF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,CAAC,KAA8B,CAAC;QAClD,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,IAAI,eAAe,EAAE,CAAC;QAC9B,CAAC;QACD,MAAM,MAAM,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
|
|
13
|
+
import { makeError, makeRequestId } from '../schemas/common.js';
|
|
14
|
+
import { log } from '../logging/logger.js';
|
|
15
|
+
import { validateTestCase } from './testCaseValidate.js';
|
|
16
|
+
// ── Shorthand → fully-qualified API ID map ────────────────────────────────────
|
|
17
|
+
// Provar runtime requires fully-qualified IDs. Shorthand forms are accepted here
|
|
18
|
+
// and expanded automatically before writing XML.
|
|
19
|
+
const SHORTHAND_TO_FQID = {
|
|
20
|
+
UiConnect: 'com.provar.plugins.forcedotcom.core.ui.UiConnect',
|
|
21
|
+
UiDoAction: 'com.provar.plugins.forcedotcom.core.ui.UiDoAction',
|
|
22
|
+
UiWithScreen: 'com.provar.plugins.forcedotcom.core.ui.UiWithScreen',
|
|
23
|
+
UiAssert: 'com.provar.plugins.forcedotcom.core.ui.UiAssert',
|
|
24
|
+
UiNavigate: 'com.provar.plugins.forcedotcom.core.ui.UiNavigate',
|
|
25
|
+
UiWithRow: 'com.provar.plugins.forcedotcom.core.ui.UiWithRow',
|
|
26
|
+
UiScrollToElement: 'com.provar.plugins.forcedotcom.core.ui.UiScrollToElement',
|
|
27
|
+
ApexConnect: 'com.provar.plugins.forcedotcom.core.testapis.ApexConnect',
|
|
28
|
+
ApexSoqlQuery: 'com.provar.plugins.forcedotcom.core.testapis.ApexSoqlQuery',
|
|
29
|
+
ApexCreateObject: 'com.provar.plugins.forcedotcom.core.testapis.ApexCreateObject',
|
|
30
|
+
ApexReadObject: 'com.provar.plugins.forcedotcom.core.testapis.ApexReadObject',
|
|
31
|
+
ApexUpdateObject: 'com.provar.plugins.forcedotcom.core.testapis.ApexUpdateObject',
|
|
32
|
+
ApexDeleteObject: 'com.provar.plugins.forcedotcom.core.testapis.ApexDeleteObject',
|
|
33
|
+
SetValues: 'com.provar.plugins.bundled.apis.control.SetValues',
|
|
34
|
+
AssertValues: 'com.provar.plugins.bundled.apis.AssertValues',
|
|
35
|
+
StepGroup: 'com.provar.plugins.bundled.apis.control.StepGroup',
|
|
36
|
+
Sleep: 'com.provar.plugins.bundled.apis.control.Sleep',
|
|
37
|
+
ForEach: 'com.provar.plugins.bundled.apis.control.ForEach',
|
|
38
|
+
CaseCall: 'com.provar.plugins.bundled.apis.control.CaseCall',
|
|
39
|
+
};
|
|
40
|
+
function resolveApiId(apiId) {
|
|
41
|
+
return SHORTHAND_TO_FQID[apiId] ?? apiId;
|
|
42
|
+
}
|
|
43
|
+
// ── Per-step runtime warnings ─────────────────────────────────────────────────
|
|
44
|
+
function buildStepWarnings(steps) {
|
|
45
|
+
const warnings = [];
|
|
46
|
+
const resolvedIds = steps.map((s) => resolveApiId(s.api_id));
|
|
47
|
+
if (resolvedIds.includes(SHORTHAND_TO_FQID['ApexReadObject'] ?? '')) {
|
|
48
|
+
warnings.push('ApexReadObject: You must specify field names in the attributes (e.g. fieldList); ' +
|
|
49
|
+
'if none are provided Provar generates "SELECT FROM ..." which throws MALFORMED_QUERY. ' +
|
|
50
|
+
'Prefer ApexSoqlQuery for full control over the SELECT clause and result binding.');
|
|
51
|
+
}
|
|
52
|
+
if (resolvedIds.includes(SHORTHAND_TO_FQID['AssertValues'] ?? '')) {
|
|
53
|
+
warnings.push('AssertValues: Direct index paths like "ResultList[0].FieldName" are NOT supported for ApexSoqlQuery results. ' +
|
|
54
|
+
'To assert SOQL results use either: (a) a ForEach loop over the result list with AssertValues inside, ' +
|
|
55
|
+
'or (b) a SetValues step to extract a specific field into a named variable, then assert that variable.');
|
|
56
|
+
}
|
|
57
|
+
return warnings;
|
|
58
|
+
}
|
|
59
|
+
// ── Schema ────────────────────────────────────────────────────────────────────
|
|
60
|
+
const StepSchema = z.object({
|
|
61
|
+
api_id: z
|
|
62
|
+
.string()
|
|
63
|
+
.describe('Provar step API ID. Shorthand forms are accepted and auto-expanded to fully-qualified IDs: ' +
|
|
64
|
+
'UiConnect, UiDoAction, UiWithScreen, UiAssert, UiNavigate, UiWithRow, ' +
|
|
65
|
+
'ApexConnect, ApexSoqlQuery, ApexCreateObject, ApexReadObject, ApexUpdateObject, ApexDeleteObject, ' +
|
|
66
|
+
'SetValues, AssertValues, StepGroup, Sleep, ForEach, CaseCall. ' +
|
|
67
|
+
'Or pass the fully-qualified ID directly (com.provar.plugins.*).'),
|
|
68
|
+
name: z.string().describe('Human-readable step name'),
|
|
69
|
+
attributes: z
|
|
70
|
+
.record(z.string())
|
|
71
|
+
.default({})
|
|
72
|
+
.describe('Step argument values as key/value pairs. Written as <arguments><argument id="key"><value .../></argument></arguments> ' +
|
|
73
|
+
'inside the <apiCall> element — the format Provar runtime requires. ' +
|
|
74
|
+
'Do NOT rely on XML attributes on <apiCall>; the runtime silently ignores them. ' +
|
|
75
|
+
'Example: { "connectionName": "MyOrg", "objectApiName": "Opportunity" }'),
|
|
76
|
+
});
|
|
77
|
+
const TOOL_DESCRIPTION = [
|
|
78
|
+
'Generate a Provar XML test case skeleton with proper UUID v4 guids, sequential testItemId values, and <steps> structure.',
|
|
79
|
+
'Returns XML content. Writes to disk only when dry_run=false.',
|
|
80
|
+
'API IDs: shorthand forms (e.g. UiConnect, ApexSoqlQuery) are automatically expanded to fully-qualified IDs required by the Provar runtime.',
|
|
81
|
+
'Step arguments: attributes are emitted as <arguments><argument id="..."><value .../></argument></arguments> — the only format the Provar runtime processes.',
|
|
82
|
+
'Shorthand XML attributes on <apiCall> are silently ignored at runtime; always supply arguments via the attributes map.',
|
|
83
|
+
'Data-driven note: <dataTable> only iterates rows when the test case runs via a test plan instance (.testinstance).',
|
|
84
|
+
'Running directly via the provardx testCase property resolves all data table variables as null.',
|
|
85
|
+
'Use provar.testplan.add-instance to wire into a plan for data-driven execution.',
|
|
86
|
+
'ApexReadObject requires field names in attributes; omitting them produces MALFORMED_QUERY. Prefer ApexSoqlQuery.',
|
|
87
|
+
'AssertValues on SOQL results: index paths like "ResultList[0].Field" are not supported.',
|
|
88
|
+
'Use ForEach to iterate the result list, or SetValues to extract a field into a variable first.',
|
|
89
|
+
'Validation: the response always includes a validation field with is_valid, validity_score, quality_score, and any structural issues — check this before attempting to run the test case.',
|
|
90
|
+
].join(' ');
|
|
91
|
+
export function registerTestCaseGenerate(server, config) {
|
|
92
|
+
server.tool('provar.testcase.generate', TOOL_DESCRIPTION, {
|
|
93
|
+
test_case_name: z.string().describe('Test case name (human-readable label)'),
|
|
94
|
+
test_case_id: z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe('Explicit test case id; auto-generated UUID v4 if omitted'),
|
|
98
|
+
steps: z.array(StepSchema).default([]).describe('Ordered list of test steps'),
|
|
99
|
+
output_path: z
|
|
100
|
+
.string()
|
|
101
|
+
.optional()
|
|
102
|
+
.describe('Suggested file path for the .xml file (returned in response)'),
|
|
103
|
+
overwrite: z.boolean().default(false).describe('Overwrite if output_path file already exists'),
|
|
104
|
+
dry_run: z
|
|
105
|
+
.boolean()
|
|
106
|
+
.default(true)
|
|
107
|
+
.describe('true = return XML only (default); false = write to output_path'),
|
|
108
|
+
idempotency_key: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe('Caller-provided key echoed back for deduplication tracking'),
|
|
112
|
+
}, (input) => {
|
|
113
|
+
const requestId = makeRequestId();
|
|
114
|
+
log('info', 'provar.testcase.generate', {
|
|
115
|
+
requestId,
|
|
116
|
+
test_case_name: input.test_case_name,
|
|
117
|
+
dry_run: input.dry_run,
|
|
118
|
+
});
|
|
119
|
+
try {
|
|
120
|
+
const xmlContent = buildTestCaseXml(input);
|
|
121
|
+
const filePath = input.output_path
|
|
122
|
+
? path.resolve(input.output_path)
|
|
123
|
+
: undefined;
|
|
124
|
+
let written = false;
|
|
125
|
+
if (filePath && !input.dry_run) {
|
|
126
|
+
assertPathAllowed(filePath, config.allowedPaths);
|
|
127
|
+
if (fs.existsSync(filePath) && !input.overwrite) {
|
|
128
|
+
const err = makeError('FILE_EXISTS', `File already exists: ${filePath}. Set overwrite=true to replace.`, requestId);
|
|
129
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
130
|
+
}
|
|
131
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
132
|
+
fs.writeFileSync(filePath, xmlContent, 'utf-8');
|
|
133
|
+
written = true;
|
|
134
|
+
log('info', 'provar.testcase.generate: wrote file', { requestId, filePath });
|
|
135
|
+
}
|
|
136
|
+
const warnings = buildStepWarnings(input.steps);
|
|
137
|
+
const validationFull = validateTestCase(xmlContent, input.test_case_name);
|
|
138
|
+
const validationSlim = {
|
|
139
|
+
is_valid: validationFull.is_valid,
|
|
140
|
+
validity_score: validationFull.validity_score,
|
|
141
|
+
quality_score: validationFull.quality_score,
|
|
142
|
+
error_count: validationFull.error_count,
|
|
143
|
+
warning_count: validationFull.warning_count,
|
|
144
|
+
issues: validationFull.issues,
|
|
145
|
+
};
|
|
146
|
+
const result = {
|
|
147
|
+
requestId,
|
|
148
|
+
xml_content: xmlContent,
|
|
149
|
+
file_path: filePath,
|
|
150
|
+
written,
|
|
151
|
+
dry_run: input.dry_run,
|
|
152
|
+
step_count: input.steps.length,
|
|
153
|
+
idempotency_key: input.idempotency_key,
|
|
154
|
+
validation: validationSlim,
|
|
155
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
156
|
+
};
|
|
157
|
+
return {
|
|
158
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
159
|
+
structuredContent: result,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
const error = err;
|
|
164
|
+
const errResult = makeError(error instanceof PathPolicyError ? error.code : (error.code ?? 'GENERATE_ERROR'), error.message, requestId, false);
|
|
165
|
+
log('error', 'provar.testcase.generate failed', { requestId, error: error.message });
|
|
166
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// ── XML builder ───────────────────────────────────────────────────────────────
|
|
171
|
+
function buildArgumentsXml(attributes) {
|
|
172
|
+
const entries = Object.entries(attributes);
|
|
173
|
+
if (entries.length === 0)
|
|
174
|
+
return '';
|
|
175
|
+
const argLines = entries
|
|
176
|
+
.map(([k, v]) => ` <argument id="${escapeXmlAttr(k)}">\n` +
|
|
177
|
+
` <value class="value" valueClass="String">${escapeXmlContent(v)}</value>\n` +
|
|
178
|
+
' </argument>')
|
|
179
|
+
.join('\n');
|
|
180
|
+
return `\n <arguments>\n${argLines}\n </arguments>\n `;
|
|
181
|
+
}
|
|
182
|
+
function buildTestCaseXml(input) {
|
|
183
|
+
const testCaseId = input.test_case_id ?? randomUUID();
|
|
184
|
+
const testCaseGuid = randomUUID();
|
|
185
|
+
const registryId = randomUUID();
|
|
186
|
+
const stepLines = input.steps
|
|
187
|
+
.map((step, i) => {
|
|
188
|
+
const guid = randomUUID();
|
|
189
|
+
const testItemId = i + 1;
|
|
190
|
+
const resolvedApiId = resolveApiId(step.api_id);
|
|
191
|
+
const argumentsXml = buildArgumentsXml(step.attributes);
|
|
192
|
+
if (argumentsXml) {
|
|
193
|
+
return (` <apiCall guid="${guid}" apiId="${escapeXmlAttr(resolvedApiId)}"` +
|
|
194
|
+
` name="${escapeXmlAttr(step.name)}" testItemId="${testItemId}">${argumentsXml}</apiCall>`);
|
|
195
|
+
}
|
|
196
|
+
return (` <apiCall guid="${guid}" apiId="${escapeXmlAttr(resolvedApiId)}"` +
|
|
197
|
+
` name="${escapeXmlAttr(step.name)}" testItemId="${testItemId}"/>`);
|
|
198
|
+
})
|
|
199
|
+
.join('\n');
|
|
200
|
+
return ('<?xml version="1.0" encoding="UTF-8"?>\n' +
|
|
201
|
+
`<testCase id="${testCaseId}" guid="${testCaseGuid}" registryId="${registryId}"` +
|
|
202
|
+
` name="${escapeXmlAttr(input.test_case_name)}">\n` +
|
|
203
|
+
' <steps>\n' +
|
|
204
|
+
(stepLines || ' <!-- TODO: Add test steps here -->') +
|
|
205
|
+
'\n </steps>\n' +
|
|
206
|
+
'</testCase>\n');
|
|
207
|
+
}
|
|
208
|
+
function escapeXmlAttr(value) {
|
|
209
|
+
return value
|
|
210
|
+
.replace(/&/g, '&')
|
|
211
|
+
.replace(/"/g, '"')
|
|
212
|
+
.replace(/</g, '<')
|
|
213
|
+
.replace(/>/g, '>');
|
|
214
|
+
}
|
|
215
|
+
function escapeXmlContent(value) {
|
|
216
|
+
return value
|
|
217
|
+
.replace(/&/g, '&')
|
|
218
|
+
.replace(/</g, '<')
|
|
219
|
+
.replace(/>/g, '>');
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=testCaseGenerate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testCaseGenerate.js","sourceRoot":"","sources":["../../../src/mcp/tools/testCaseGenerate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ServerConfig } from '../server.js';
|
|
3
|
+
import { type ValidationIssue } from '../schemas/common.js';
|
|
4
|
+
export declare function registerTestCaseValidate(server: McpServer, config: ServerConfig): void;
|
|
5
|
+
export interface TestCaseValidationResult {
|
|
6
|
+
is_valid: boolean;
|
|
7
|
+
validity_score: number;
|
|
8
|
+
quality_score: number;
|
|
9
|
+
test_case_id: string | null;
|
|
10
|
+
test_case_name: string | null;
|
|
11
|
+
step_count: number;
|
|
12
|
+
error_count: number;
|
|
13
|
+
warning_count: number;
|
|
14
|
+
issues: ValidationIssue[];
|
|
15
|
+
/** Violations from the Best Practices Engine (same rules as the Quality Hub API). */
|
|
16
|
+
best_practices_violations?: Array<import('./bestPracticesEngine.js').BPViolation>;
|
|
17
|
+
best_practices_rules_evaluated?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Pure function — exported for unit testing */
|
|
20
|
+
export declare function validateTestCase(xmlContent: string, testName?: string): TestCaseValidationResult;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
12
|
+
import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
|
|
13
|
+
import { makeError, makeRequestId } from '../schemas/common.js';
|
|
14
|
+
import { log } from '../logging/logger.js';
|
|
15
|
+
import { runBestPractices } from './bestPracticesEngine.js';
|
|
16
|
+
export function registerTestCaseValidate(server, config) {
|
|
17
|
+
server.tool('provar.testcase.validate', 'Validate a Provar XML test case for structural correctness and quality. Checks XML declaration, root element, required attributes (guid UUID v4, testItemId integer), <steps> presence, and applies best-practice rules (same ruleset and scoring as the Quality Hub batch validation API). Returns validity_score (schema compliance) and quality_score (best practices, 0–100).', {
|
|
18
|
+
content: z.string().optional().describe('XML content to validate directly (alias: xml)'),
|
|
19
|
+
xml: z.string().optional().describe('XML content to validate — API-compatible alias for content'),
|
|
20
|
+
file_path: z.string().optional().describe('Path to .xml test case file'),
|
|
21
|
+
}, ({ content, xml, file_path }) => {
|
|
22
|
+
const requestId = makeRequestId();
|
|
23
|
+
log('info', 'provar.testcase.validate', { requestId, has_content: !!content, file_path });
|
|
24
|
+
try {
|
|
25
|
+
// Resolve xml alias: the batch validation API uses "xml", MCP originally used "content"
|
|
26
|
+
let source = content ?? xml;
|
|
27
|
+
if (!source && file_path) {
|
|
28
|
+
assertPathAllowed(file_path, config.allowedPaths);
|
|
29
|
+
const resolved = path.resolve(file_path);
|
|
30
|
+
if (!fs.existsSync(resolved)) {
|
|
31
|
+
const err = makeError('FILE_NOT_FOUND', `File not found: ${resolved}`, requestId);
|
|
32
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
33
|
+
}
|
|
34
|
+
source = fs.readFileSync(resolved, 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
if (!source) {
|
|
37
|
+
const err = makeError('MISSING_INPUT', 'Provide either content or file_path.', requestId);
|
|
38
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
|
|
39
|
+
}
|
|
40
|
+
const validation = validateTestCase(source);
|
|
41
|
+
const result = { requestId, ...validation };
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
44
|
+
structuredContent: result,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const error = err;
|
|
49
|
+
const errResult = makeError(error instanceof PathPolicyError ? error.code : 'VALIDATE_ERROR', error.message, requestId, false);
|
|
50
|
+
log('error', 'provar.testcase.validate failed', { requestId, error: error.message });
|
|
51
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(errResult) }] };
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// ── Validator (ported from quality-hub-agents/lambda/src/validator/handler.py) ──
|
|
56
|
+
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
57
|
+
/** Pure function — exported for unit testing */
|
|
58
|
+
export function validateTestCase(xmlContent, testName) {
|
|
59
|
+
const issues = [];
|
|
60
|
+
// TC_001: XML declaration
|
|
61
|
+
if (!xmlContent.trimStart().startsWith('<?xml')) {
|
|
62
|
+
issues.push({
|
|
63
|
+
rule_id: 'TC_001', severity: 'ERROR',
|
|
64
|
+
message: 'Missing XML declaration. File must start with <?xml version="1.0" encoding="UTF-8"?>.',
|
|
65
|
+
applies_to: 'document',
|
|
66
|
+
suggestion: 'Add XML declaration as the first line.',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// Parse
|
|
70
|
+
const parser = new XMLParser({
|
|
71
|
+
ignoreAttributes: false,
|
|
72
|
+
attributeNamePrefix: '@_',
|
|
73
|
+
parseAttributeValue: false,
|
|
74
|
+
});
|
|
75
|
+
let parsed;
|
|
76
|
+
try {
|
|
77
|
+
parsed = parser.parse(xmlContent);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
const parseError = e;
|
|
81
|
+
issues.push({
|
|
82
|
+
rule_id: 'TC_002', severity: 'ERROR',
|
|
83
|
+
message: `XML parse error: ${parseError.message}`,
|
|
84
|
+
applies_to: 'document',
|
|
85
|
+
suggestion: 'Fix XML syntax errors.',
|
|
86
|
+
});
|
|
87
|
+
return finalize(issues, null, null, 0, xmlContent, testName);
|
|
88
|
+
}
|
|
89
|
+
// TC_003: Root element
|
|
90
|
+
if (!('testCase' in parsed)) {
|
|
91
|
+
issues.push({
|
|
92
|
+
rule_id: 'TC_003', severity: 'ERROR',
|
|
93
|
+
message: 'Root element must be <testCase>.',
|
|
94
|
+
applies_to: 'document',
|
|
95
|
+
suggestion: 'Ensure root element is <testCase>.',
|
|
96
|
+
});
|
|
97
|
+
return finalize(issues, null, null, 0, xmlContent, testName);
|
|
98
|
+
}
|
|
99
|
+
const tc = parsed['testCase'];
|
|
100
|
+
const tcId = tc['@_id'] ?? null;
|
|
101
|
+
const tcName = tc['@_name'] ?? null;
|
|
102
|
+
const tcGuid = tc['@_guid'];
|
|
103
|
+
if (!tcId) {
|
|
104
|
+
issues.push({
|
|
105
|
+
rule_id: 'TC_010', severity: 'ERROR',
|
|
106
|
+
message: 'testCase missing required id attribute.',
|
|
107
|
+
applies_to: 'testCase',
|
|
108
|
+
suggestion: 'Add id attribute to testCase element.',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!tcGuid) {
|
|
112
|
+
issues.push({
|
|
113
|
+
rule_id: 'TC_011', severity: 'ERROR',
|
|
114
|
+
message: 'testCase missing required guid attribute.',
|
|
115
|
+
applies_to: 'testCase',
|
|
116
|
+
suggestion: 'Add guid attribute (UUID v4) to testCase element.',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
else if (!UUID_V4_RE.test(tcGuid)) {
|
|
120
|
+
issues.push({
|
|
121
|
+
rule_id: 'TC_012', severity: 'ERROR',
|
|
122
|
+
message: `testCase guid "${tcGuid}" is not a valid UUID v4.`,
|
|
123
|
+
applies_to: 'testCase',
|
|
124
|
+
suggestion: 'Generate a proper UUID v4 for the guid attribute.',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// TC_013 (registryId) is intentionally not checked here — registryId is a
|
|
128
|
+
// Salesforce Quality Hub record ID assigned when a test case is registered in
|
|
129
|
+
// the QH org. Local project files will never have this attribute, so checking
|
|
130
|
+
// for it produces a universal false positive for every test case.
|
|
131
|
+
// TC_020: <steps> element
|
|
132
|
+
if (!('steps' in tc)) {
|
|
133
|
+
issues.push({
|
|
134
|
+
rule_id: 'TC_020', severity: 'ERROR',
|
|
135
|
+
message: 'testCase missing <steps> element.',
|
|
136
|
+
applies_to: 'testCase',
|
|
137
|
+
suggestion: 'Wrap all step elements in a <steps> element.',
|
|
138
|
+
});
|
|
139
|
+
return finalize(issues, tcId, tcName, 0, xmlContent, testName);
|
|
140
|
+
}
|
|
141
|
+
const steps = tc['steps'];
|
|
142
|
+
const rawApiCalls = steps['apiCall'];
|
|
143
|
+
const apiCalls = rawApiCalls
|
|
144
|
+
? (Array.isArray(rawApiCalls) ? rawApiCalls : [rawApiCalls])
|
|
145
|
+
: [];
|
|
146
|
+
for (const call of apiCalls) {
|
|
147
|
+
validateApiCall(call, issues);
|
|
148
|
+
}
|
|
149
|
+
return finalize(issues, tcId, tcName, apiCalls.length, xmlContent, testName);
|
|
150
|
+
}
|
|
151
|
+
function validateApiCall(call, issues) {
|
|
152
|
+
const callGuid = call['@_guid'];
|
|
153
|
+
const apiId = call['@_apiId'];
|
|
154
|
+
const name = call['@_name'];
|
|
155
|
+
const testItemId = call['@_testItemId'];
|
|
156
|
+
const label = apiId ? ` "${apiId}"` : '';
|
|
157
|
+
if (!callGuid) {
|
|
158
|
+
issues.push({
|
|
159
|
+
rule_id: 'TC_030', severity: 'ERROR',
|
|
160
|
+
message: `apiCall${label} missing guid attribute.`,
|
|
161
|
+
applies_to: 'apiCall',
|
|
162
|
+
suggestion: 'Add a UUID v4 guid to each apiCall.',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else if (!UUID_V4_RE.test(callGuid)) {
|
|
166
|
+
issues.push({
|
|
167
|
+
rule_id: 'TC_031', severity: 'ERROR',
|
|
168
|
+
message: `apiCall${label} guid "${callGuid}" is not a valid UUID v4.`,
|
|
169
|
+
applies_to: 'apiCall',
|
|
170
|
+
suggestion: 'Use proper UUID v4 format.',
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (!apiId) {
|
|
174
|
+
issues.push({
|
|
175
|
+
rule_id: 'TC_032', severity: 'ERROR',
|
|
176
|
+
message: 'apiCall missing apiId attribute.',
|
|
177
|
+
applies_to: 'apiCall',
|
|
178
|
+
suggestion: 'Add apiId attribute (e.g., UiConnect, ApexSoqlQuery).',
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (!name) {
|
|
182
|
+
issues.push({
|
|
183
|
+
rule_id: 'TC_033', severity: 'WARNING',
|
|
184
|
+
message: `apiCall${label} missing name attribute.`,
|
|
185
|
+
applies_to: 'apiCall',
|
|
186
|
+
suggestion: 'Add a descriptive name attribute.',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (!testItemId) {
|
|
190
|
+
issues.push({
|
|
191
|
+
rule_id: 'TC_034', severity: 'ERROR',
|
|
192
|
+
message: `apiCall${label} missing testItemId attribute.`,
|
|
193
|
+
applies_to: 'apiCall',
|
|
194
|
+
suggestion: 'Add sequential testItemId (1, 2, 3...).',
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else if (!/^\d+$/.test(testItemId)) {
|
|
198
|
+
issues.push({
|
|
199
|
+
rule_id: 'TC_035', severity: 'ERROR',
|
|
200
|
+
message: `apiCall${label} testItemId "${testItemId}" must be a whole number.`,
|
|
201
|
+
applies_to: 'apiCall',
|
|
202
|
+
suggestion: 'Use sequential integers for testItemId.',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function finalize(issues, testCaseId, testCaseName, stepCount, xmlContent, testName) {
|
|
207
|
+
const errorCount = issues.filter((i) => i.severity === 'ERROR').length;
|
|
208
|
+
const warningCount = issues.filter((i) => i.severity === 'WARNING').length;
|
|
209
|
+
// Layer 1: validity score (schema compliance — existing rules)
|
|
210
|
+
const validity_score = Math.max(0, 100 - errorCount * 20);
|
|
211
|
+
// Layer 2: quality score (best practices engine — same rules & formula as Quality Hub API)
|
|
212
|
+
const bp = runBestPractices(xmlContent, { testName });
|
|
213
|
+
return {
|
|
214
|
+
is_valid: errorCount === 0,
|
|
215
|
+
validity_score,
|
|
216
|
+
quality_score: bp.quality_score,
|
|
217
|
+
test_case_id: testCaseId,
|
|
218
|
+
test_case_name: testCaseName,
|
|
219
|
+
step_count: stepCount,
|
|
220
|
+
error_count: errorCount,
|
|
221
|
+
warning_count: warningCount,
|
|
222
|
+
issues,
|
|
223
|
+
best_practices_violations: bp.violations,
|
|
224
|
+
best_practices_rules_evaluated: bp.rules_evaluated,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=testCaseValidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testCaseValidate.js","sourceRoot":"","sources":["../../../src/mcp/tools/testCaseValidate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAwB,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,MAAoB;IAC9E,MAAM,CAAC,IAAI,CACT,0BAA0B,EAC1B,mXAAmX,EACnX;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACxF,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;QACjG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;KACzE,EACD,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE;QAC9B,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;QAClC,GAAG,CAAC,MAAM,EAAE,0BAA0B,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1F,IAAI,CAAC;YACH,wFAAwF;YACxF,IAAI,MAAM,GAAG,OAAO,IAAI,GAAG,CAAC;YAE5B,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;gBACzB,iBAAiB,CAAC,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC;oBAClF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5F,CAAC;gBACD,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9C,CAAC;YAED,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,SAAS,CAAC,eAAe,EAAE,sCAAsC,EAAE,SAAS,CAAC,CAAC;gBAC1F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5F,CAAC;YAED,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;YAC5C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAAM;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,GAAgC,CAAC;YAC/C,MAAM,SAAS,GAAG,SAAS,CACzB,KAAK,YAAY,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,EAChE,KAAK,CAAC,OAAO,EACb,SAAS,EACT,KAAK,CACN,CAAC;YACF,GAAG,CAAC,OAAO,EAAE,iCAAiC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACrF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;QAClG,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,mFAAmF;AAEnF,MAAM,UAAU,GAAG,wEAAwE,CAAC;AAiB5F,gDAAgD;AAChD,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,QAAiB;IACpE,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,0BAA0B;IAC1B,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,uFAAuF;YAChG,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,wCAAwC;SACrD,CAAC,CAAC;IACL,CAAC;IAED,QAAQ;IACR,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,gBAAgB,EAAE,KAAK;QACvB,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IACH,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAA4B,CAAC;IAC/D,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,CAAU,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,oBAAoB,UAAU,CAAC,OAAO,EAAE;YACjD,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,wBAAwB;SACrC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAED,uBAAuB;IACvB,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,kCAAkC;YAC3C,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,oCAAoC;SACjD,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAA4B,CAAC;IACzD,MAAM,IAAI,GAAI,EAAE,CAAC,MAAM,CAAwB,IAAI,IAAI,CAAC;IACxD,MAAM,MAAM,GAAI,EAAE,CAAC,QAAQ,CAAwB,IAAI,IAAI,CAAC;IAC5D,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAuB,CAAC;IAElD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,yCAAyC;YAClD,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,uCAAuC;SACpD,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,2CAA2C;YACpD,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,mDAAmD;SAChE,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,kBAAkB,MAAM,2BAA2B;YAC5D,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,mDAAmD;SAChE,CAAC,CAAC;IACL,CAAC;IACD,0EAA0E;IAC1E,8EAA8E;IAC9E,8EAA8E;IAC9E,kEAAkE;IAElE,0BAA0B;IAC1B,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,mCAAmC;YAC5C,UAAU,EAAE,UAAU;YACtB,UAAU,EAAE,8CAA8C;SAC3D,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAA4B,CAAC;IACrD,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAmC,WAAW;QAC1D,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAmC;QAC9F,CAAC,CAAC,EAAE,CAAC;IAEP,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,eAAe,CAAC,IAA6B,EAAE,MAAyB;IAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAuB,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAuB,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAuB,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAuB,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,UAAU,KAAK,0BAA0B;YAClD,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,qCAAqC;SAClD,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,UAAU,KAAK,UAAU,QAAQ,2BAA2B;YACrE,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,4BAA4B;SACzC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,kCAAkC;YAC3C,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,uDAAuD;SACpE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS;YACtC,OAAO,EAAE,UAAU,KAAK,0BAA0B;YAClD,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,mCAAmC;SAChD,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,UAAU,KAAK,gCAAgC;YACxD,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,yCAAyC;SACtD,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC;YACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;YACpC,OAAO,EAAE,UAAU,KAAK,gBAAgB,UAAU,2BAA2B;YAC7E,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,yCAAyC;SACtD,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CACf,MAAyB,EACzB,UAAyB,EACzB,YAA2B,EAC3B,SAAiB,EACjB,UAAkB,EAClB,QAAiB;IAEjB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAE3E,+DAA+D;IAC/D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,UAAU,GAAG,EAAE,CAAC,CAAC;IAE1D,2FAA2F;IAC3F,MAAM,EAAE,GAAG,gBAAgB,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEtD,OAAO;QACL,QAAQ,EAAE,UAAU,KAAK,CAAC;QAC1B,cAAc;QACd,aAAa,EAAE,EAAE,CAAC,aAAa;QAC/B,YAAY,EAAE,UAAU;QACxB,cAAc,EAAE,YAAY;QAC5B,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,UAAU;QACvB,aAAa,EAAE,YAAY;QAC3B,MAAM;QACN,yBAAyB,EAAE,EAAE,CAAC,UAAU;QACxC,8BAA8B,EAAE,EAAE,CAAC,eAAe;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ServerConfig } from '../server.js';
|
|
3
|
+
export declare function registerTestPlanAddInstance(server: McpServer, config: ServerConfig): void;
|
|
4
|
+
export declare function registerTestPlanCreateSuite(server: McpServer, config: ServerConfig): void;
|
|
5
|
+
export declare function registerTestPlanRemoveInstance(server: McpServer, config: ServerConfig): void;
|
|
6
|
+
export declare function registerAllTestPlanTools(server: McpServer, config: ServerConfig): void;
|