@provartesting/provardx-cli 1.5.0 → 1.5.2

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.
Files changed (78) hide show
  1. package/lib/mcp/docs/PROVAR_TOOL_GUIDE.md +18 -6
  2. package/lib/mcp/prompts/guidePrompts.js +21 -11
  3. package/lib/mcp/prompts/guidePrompts.js.map +1 -1
  4. package/lib/mcp/server.d.ts +1 -0
  5. package/lib/mcp/server.js +90 -21
  6. package/lib/mcp/server.js.map +1 -1
  7. package/lib/mcp/tools/antTools.d.ts +20 -0
  8. package/lib/mcp/tools/antTools.js +105 -41
  9. package/lib/mcp/tools/antTools.js.map +1 -1
  10. package/lib/mcp/tools/automationTools.js +65 -35
  11. package/lib/mcp/tools/automationTools.js.map +1 -1
  12. package/lib/mcp/tools/connectionTools.js +100 -30
  13. package/lib/mcp/tools/connectionTools.js.map +1 -1
  14. package/lib/mcp/tools/defectTools.js +12 -7
  15. package/lib/mcp/tools/defectTools.js.map +1 -1
  16. package/lib/mcp/tools/descHelper.d.ts +5 -0
  17. package/lib/mcp/tools/descHelper.js +14 -0
  18. package/lib/mcp/tools/descHelper.js.map +1 -0
  19. package/lib/mcp/tools/nitroXTools.js +72 -32
  20. package/lib/mcp/tools/nitroXTools.js.map +1 -1
  21. package/lib/mcp/tools/orgDescribeTools.d.ts +57 -0
  22. package/lib/mcp/tools/orgDescribeTools.js +329 -0
  23. package/lib/mcp/tools/orgDescribeTools.js.map +1 -0
  24. package/lib/mcp/tools/pageObjectGenerate.js +33 -15
  25. package/lib/mcp/tools/pageObjectGenerate.js.map +1 -1
  26. package/lib/mcp/tools/pageObjectValidate.js +11 -4
  27. package/lib/mcp/tools/pageObjectValidate.js.map +1 -1
  28. package/lib/mcp/tools/projectInspect.js +31 -5
  29. package/lib/mcp/tools/projectInspect.js.map +1 -1
  30. package/lib/mcp/tools/projectValidateFromPath.js +128 -22
  31. package/lib/mcp/tools/projectValidateFromPath.js.map +1 -1
  32. package/lib/mcp/tools/propertiesTools.d.ts +12 -0
  33. package/lib/mcp/tools/propertiesTools.js +155 -17
  34. package/lib/mcp/tools/propertiesTools.js.map +1 -1
  35. package/lib/mcp/tools/qualityHubApiTools.js +8 -7
  36. package/lib/mcp/tools/qualityHubApiTools.js.map +1 -1
  37. package/lib/mcp/tools/qualityHubTools.js +108 -37
  38. package/lib/mcp/tools/qualityHubTools.js.map +1 -1
  39. package/lib/mcp/tools/rcaTools.d.ts +17 -0
  40. package/lib/mcp/tools/rcaTools.js +69 -15
  41. package/lib/mcp/tools/rcaTools.js.map +1 -1
  42. package/lib/mcp/tools/testCaseGenerate.d.ts +1 -0
  43. package/lib/mcp/tools/testCaseGenerate.js +116 -13
  44. package/lib/mcp/tools/testCaseGenerate.js.map +1 -1
  45. package/lib/mcp/tools/testCaseStepTools.js +27 -9
  46. package/lib/mcp/tools/testCaseStepTools.js.map +1 -1
  47. package/lib/mcp/tools/testCaseValidate.d.ts +14 -1
  48. package/lib/mcp/tools/testCaseValidate.js +190 -69
  49. package/lib/mcp/tools/testCaseValidate.js.map +1 -1
  50. package/lib/mcp/tools/testPlanTools.js +43 -26
  51. package/lib/mcp/tools/testPlanTools.js.map +1 -1
  52. package/lib/mcp/tools/testPlanValidate.js +64 -11
  53. package/lib/mcp/tools/testPlanValidate.js.map +1 -1
  54. package/lib/mcp/tools/testSuiteValidate.js +99 -10
  55. package/lib/mcp/tools/testSuiteValidate.js.map +1 -1
  56. package/lib/mcp/utils/detailLevel.d.ts +9 -0
  57. package/lib/mcp/utils/detailLevel.js +20 -0
  58. package/lib/mcp/utils/detailLevel.js.map +1 -0
  59. package/lib/mcp/utils/fieldMask.d.ts +17 -0
  60. package/lib/mcp/utils/fieldMask.js +75 -0
  61. package/lib/mcp/utils/fieldMask.js.map +1 -0
  62. package/lib/mcp/utils/testCasePlanMode.d.ts +41 -0
  63. package/lib/mcp/utils/testCasePlanMode.js +208 -0
  64. package/lib/mcp/utils/testCasePlanMode.js.map +1 -0
  65. package/lib/mcp/utils/tokenMeta.d.ts +40 -0
  66. package/lib/mcp/utils/tokenMeta.js +90 -0
  67. package/lib/mcp/utils/tokenMeta.js.map +1 -0
  68. package/lib/mcp/utils/validationDiff.d.ts +57 -0
  69. package/lib/mcp/utils/validationDiff.js +191 -0
  70. package/lib/mcp/utils/validationDiff.js.map +1 -0
  71. package/lib/mcp/utils/validationScore.d.ts +15 -0
  72. package/lib/mcp/utils/validationScore.js +31 -0
  73. package/lib/mcp/utils/validationScore.js.map +1 -0
  74. package/lib/mcp/utils/warningCodes.d.ts +10 -0
  75. package/lib/mcp/utils/warningCodes.js +19 -0
  76. package/lib/mcp/utils/warningCodes.js.map +1 -0
  77. package/oclif.manifest.json +1 -1
  78. package/package.json +13 -1
@@ -77,15 +77,27 @@ provar_properties_set { file_path: "<output_path>", key: "connectionName", valu
77
77
 
78
78
  ## "I want to write a new test"
79
79
 
80
+ A Provar test case is a tree (scenarios → UI screens → asserts), not a flat list of steps. The agent that calls `provar_testcase_generate` is responsible for constructing the full tree in **one** call. Splitting authoring across many tool calls causes scenario numbering drift, flat asserts, and inconsistent step types — `provar_testcase_step_edit` is for **amending** an existing test case, not for **constructing** one.
81
+
82
+ Recommended sequence:
83
+
80
84
  ```
81
- 1. provar_project_inspect { project_path } ← find coverage gaps first
82
- 2. provar_testcase_generate { project_path, name, ... }
83
- 3. provar_testcase_step_edit { test_case_path, ... } repeat per step
84
- 4. provar_testcase_validate { file_path } ← must pass before adding to plan
85
- 5. provar_testplan_add-instance { project_path, plan_name, test_case_path }
86
- 6. provar_testplan_validate { project_path, plan_name }
85
+ 1. provar_project_inspect { project_path } ← find coverage gaps first
86
+ 2. provar_qualityhub_examples_retrieve { object_or_scenario } ← ground in corpus examples for the step types you need
87
+ 3. provar_testcase_generate { test_case_name, steps: [<ALL steps>] } single call, full step tree in one payload
88
+ 4. provar_testcase_validate { file_path } ← must pass before adding to plan
89
+ 5. provar_testplan_add-instance { project_path, plan_name, test_case_path }
90
+ 6. provar_testplan_validate { project_path, plan_name }
87
91
  ```
88
92
 
93
+ Use `provar_testcase_step_edit` only when:
94
+
95
+ - Adding a single step to an existing, already-validated test case
96
+ - Fixing a step's attributes after a validation finding
97
+ - Targeted edits during debugging
98
+
99
+ Do **not** use `provar_testcase_step_edit` to construct a test case step-by-step from an empty skeleton — the LLM loses scenario context between calls and the resulting structure is unreliable.
100
+
89
101
  ---
90
102
 
91
103
  ## "I want to work with Salesforce metadata"
@@ -225,16 +225,23 @@ Required sequence — do not skip steps:
225
225
  6. provar_qualityhub_defect_create → optional, create defects for failures`,
226
226
  'author-test': `## Author a New Test Case
227
227
 
228
- 1. provar_project_inspect → find coverage gaps before writing
229
- 2. provar_automation_metadata_download → if SF metadata is stale (missing fields/objects)
230
- 3. provar_pageobject_generate if a new page object is needed
231
- 4. provar_pageobject_validate → validate before compile
232
- 5. provar_automation_compile after any page object change
233
- 6. provar_testcase_generate create the test case file
234
- 7. provar_testcase_step_edit add steps (repeat as needed)
235
- 8. provar_testcase_validate MUST pass before adding to a plan
236
- 9. provar_testplan_add-instance add to an existing plan
237
- 10. provar_testplan_validate validate the plan`,
228
+ Construct the full step tree in a single \`provar_testcase_generate\` call.
229
+ \`provar_testcase_step_edit\` is for amending an existing case, not for
230
+ building one step-by-step (that pattern drops scenarios and flattens nesting).
231
+
232
+ 1. provar_project_inspect find coverage gaps before writing
233
+ 2. provar_qualityhub_examples_retrieve ground in corpus examples for the step types you need
234
+ 3. provar_automation_metadata_download if SF metadata is stale (missing fields/objects)
235
+ 4. provar_pageobject_generate only if a new page object is needed
236
+ 5. provar_pageobject_validate validate before compile
237
+ 6. provar_automation_compile after any page object change
238
+ 7. provar_testcase_generate → single call, pass ALL steps in one payload
239
+ 8. provar_testcase_validate → MUST pass before adding to a plan
240
+ 9. provar_testplan_add-instance → add to an existing plan
241
+ 10. provar_testplan_validate → validate the plan
242
+
243
+ Use provar_testcase_step_edit only to amend an existing validated test case
244
+ (single-step add, attribute fix, debug edit) — never to construct one from scratch.`,
238
245
  'debug-failures': `## Debug Failing Tests
239
246
 
240
247
  1. provar_testrun_report_locate → find the report file
@@ -278,11 +285,14 @@ provar_pageobject_validate
278
285
  provar_nitrox_generate OR provar_nitrox_patch
279
286
  └── provar_nitrox_validate (always validate after)
280
287
 
281
- provar_testcase_generate OR provar_testcase_step_edit
288
+ provar_testcase_generate (construct full case — pass ALL steps in one call)
282
289
  └── provar_testcase_validate
283
290
  └── provar_testplan_add-instance
284
291
  └── provar_testplan_validate
285
292
 
293
+ provar_testcase_step_edit (amend an existing validated case only — never construct)
294
+ └── provar_testcase_validate
295
+
286
296
  ### Safe to run in parallel (no dependency between them)
287
297
  - provar_project_inspect + provar_connection_list
288
298
  - provar_pageobject_validate on multiple files
@@ -1 +1 @@
1
- {"version":3,"file":"guidePrompts.js","sourceRoot":"","sources":["../../../src/mcp/prompts/guidePrompts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guidePrompts.js","sourceRoot":"","sources":["../../../src/mcp/prompts/guidePrompts.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export interface ServerConfig {
7
7
  updateCommand: string | null;
8
8
  };
9
9
  }
10
+ export declare function parseActiveGroups(): Set<string> | null;
10
11
  export declare function createProvarMcpServer(config: ServerConfig): McpServer;
11
12
  /**
12
13
  * Resolve the docs directory for bundled MCP Markdown resources.
package/lib/mcp/server.js CHANGED
@@ -32,7 +32,72 @@ import { registerAllTestPlanTools } from './tools/testPlanTools.js';
32
32
  import { registerAllNitroXTools } from './tools/nitroXTools.js';
33
33
  import { registerAllTestCaseStepTools } from './tools/testCaseStepTools.js';
34
34
  import { registerAllConnectionTools } from './tools/connectionTools.js';
35
+ import { registerAllOrgDescribeTools } from './tools/orgDescribeTools.js';
35
36
  import { registerAllPrompts } from './prompts/index.js';
37
+ import { createDepthGuardState, wrapWithDepthGuard, } from './utils/tokenMeta.js';
38
+ import { desc } from './tools/descHelper.js';
39
+ // ── Tool group registry ───────────────────────────────────────────────────────
40
+ // Groups are keyed in lowercase so they match the lowercased env var values.
41
+ const TOOL_GROUPS = {
42
+ nitrox: [registerAllNitroXTools],
43
+ automation: [registerAllAutomationTools],
44
+ qualityhub: [registerAllQualityHubTools, registerAllQualityHubApiTools, registerAllDefectTools],
45
+ validation: [
46
+ registerProjectValidateFromPath,
47
+ registerAllAntTools,
48
+ registerAllPropertiesTools,
49
+ registerTestCaseValidate,
50
+ registerTestSuiteValidate,
51
+ registerTestPlanValidate,
52
+ registerPageObjectValidate,
53
+ ],
54
+ authoring: [
55
+ registerTestCaseGenerate,
56
+ registerPageObjectGenerate,
57
+ registerAllTestCaseStepTools,
58
+ registerAllTestPlanTools,
59
+ ],
60
+ inspect: [registerProjectInspect, registerAllOrgDescribeTools],
61
+ connection: [registerAllConnectionTools],
62
+ rca: [registerAllRcaTools],
63
+ };
64
+ export function parseActiveGroups() {
65
+ const env = process.env['PROVAR_MCP_TOOLS'];
66
+ if (!env?.trim())
67
+ return null;
68
+ const requested = new Set(env
69
+ .split(',')
70
+ .map((g) => g.trim().toLowerCase())
71
+ .filter(Boolean));
72
+ if (requested.size === 0) {
73
+ log('warn', 'PROVAR_MCP_TOOLS was set but contained no valid group names — activating all groups', { raw: env });
74
+ return null;
75
+ }
76
+ const known = new Set(Object.keys(TOOL_GROUPS));
77
+ const matched = new Set();
78
+ const unknown = [];
79
+ for (const g of requested) {
80
+ if (known.has(g))
81
+ matched.add(g);
82
+ else
83
+ unknown.push(g);
84
+ }
85
+ if (unknown.length > 0) {
86
+ log('warn', 'PROVAR_MCP_TOOLS contains unknown group names — they will be ignored', {
87
+ raw: env,
88
+ unknown,
89
+ known: [...known],
90
+ });
91
+ }
92
+ if (matched.size === 0) {
93
+ log('warn', 'PROVAR_MCP_TOOLS matched no known group names — activating all groups', {
94
+ raw: env,
95
+ known: [...known],
96
+ });
97
+ return null;
98
+ }
99
+ return matched;
100
+ }
36
101
  export function createProvarMcpServer(config) {
37
102
  log('info', 'Creating Provar MCP server', { allowedPaths: config.allowedPaths });
38
103
  const server = new McpServer({
@@ -42,9 +107,13 @@ export function createProvarMcpServer(config) {
42
107
  // ── Sanity-check tool ────────────────────────────────────────────────────────
43
108
  server.registerTool('provardx_ping', {
44
109
  title: 'Ping MCP Server',
45
- description: 'Sanity-check tool. Echoes back a message with a timestamp. Use this to verify the MCP server is reachable before calling other tools.',
110
+ description: desc('Sanity-check tool. Echoes back a message with a timestamp. Use this to verify the MCP server is reachable before calling other tools.', 'Echo message back with timestamp; verify MCP server is reachable.'),
46
111
  inputSchema: {
47
- message: z.string().optional().default('ping').describe('Optional message to echo back'),
112
+ message: z
113
+ .string()
114
+ .optional()
115
+ .default('ping')
116
+ .describe(desc('Optional message to echo back', 'message to echo')),
48
117
  },
49
118
  }, ({ message }) => {
50
119
  const result = {
@@ -60,26 +129,20 @@ export function createProvarMcpServer(config) {
60
129
  structuredContent: result,
61
130
  };
62
131
  });
132
+ // ── Depth-guard middleware (PDX-474) ─────────────────────────────────────────
133
+ const rawLimit = parseInt(process.env['PROVAR_MCP_MAX_TOOL_DEPTH'] ?? '50', 10);
134
+ const depthLimit = Number.isNaN(rawLimit) || rawLimit <= 0 ? 50 : rawLimit;
135
+ const depthState = createDepthGuardState();
136
+ patchWithMiddleware(server, depthState, depthLimit);
63
137
  // ── Provar tools ─────────────────────────────────────────────────────────────
64
- registerProjectInspect(server, config);
65
- registerPageObjectGenerate(server, config);
66
- registerPageObjectValidate(server, config);
67
- registerTestCaseGenerate(server, config);
68
- registerTestCaseValidate(server, config);
69
- registerTestSuiteValidate(server);
70
- registerTestPlanValidate(server);
71
- registerProjectValidateFromPath(server, config);
72
- registerAllPropertiesTools(server, config);
73
- registerAllQualityHubTools(server);
74
- registerAllQualityHubApiTools(server);
75
- registerAllAutomationTools(server, config);
76
- registerAllDefectTools(server);
77
- registerAllAntTools(server, config);
78
- registerAllRcaTools(server, config);
79
- registerAllTestPlanTools(server, config);
80
- registerAllNitroXTools(server, config);
81
- registerAllTestCaseStepTools(server, config);
82
- registerAllConnectionTools(server, config);
138
+ const activeGroups = parseActiveGroups();
139
+ for (const [group, registrars] of Object.entries(TOOL_GROUPS)) {
140
+ if (activeGroups === null || activeGroups.has(group)) {
141
+ for (const register of registrars) {
142
+ register(server, config);
143
+ }
144
+ }
145
+ }
83
146
  // ── Provar prompts ───────────────────────────────────────────────────────────
84
147
  registerAllPrompts(server);
85
148
  // ── Documentation resources ──────────────────────────────────────────────────
@@ -167,6 +230,12 @@ export function createProvarMcpServer(config) {
167
230
  });
168
231
  return server;
169
232
  }
233
+ function patchWithMiddleware(server, state, limit) {
234
+ const orig = server.registerTool.bind(server);
235
+ // Cast through unknown to patch the overloaded method without triggering no-unsafe-any.
236
+ const patchable = server;
237
+ patchable.registerTool = (name, config, handler) => orig(name, config, wrapWithDepthGuard(name, handler, state, limit));
238
+ }
170
239
  /**
171
240
  * Resolve the docs directory for bundled MCP Markdown resources.
172
241
  * In compiled output (lib/mcp/) the sibling docs/ dir exists; in dev/ts-node
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -18,15 +18,35 @@ export interface AntValidationResult {
18
18
  }
19
19
  /** Pure function — exported for unit testing */
20
20
  export declare function validateAntXml(xmlContent: string): AntValidationResult;
21
+ export type JUnitErrorCategory = 'INFRASTRUCTURE' | 'ASSERTION' | 'LOCATOR' | 'TIMEOUT' | 'OTHER';
21
22
  export interface JUnitStepResult {
22
23
  testItemId: string;
23
24
  title: string;
24
25
  status: 'pass' | 'fail' | 'skip';
25
26
  errorMessage?: string;
27
+ error_category?: JUnitErrorCategory;
28
+ retryable?: boolean;
26
29
  }
30
+ /**
31
+ * Classify a failure message into a coarse-grained category used for retry decisions.
32
+ * Mirrors the classifier in rcaTools.ts (PDX-490) so a downstream consumer sees the
33
+ * same labelling whether they consume `provar_automation_testrun.steps[]` or
34
+ * `provar_testrun_rca.failures[]`.
35
+ *
36
+ * Returns `undefined` when no pattern matches.
37
+ */
38
+ export declare function classifyStepErrorCategory(errorText: string): JUnitErrorCategory | undefined;
39
+ /** Only transient categories (INFRASTRUCTURE, TIMEOUT) are retryable. */
40
+ export declare function isStepRetryable(category: JUnitErrorCategory | undefined): boolean | undefined;
27
41
  export interface JUnitParseResult {
28
42
  steps: JUnitStepResult[];
29
43
  warning?: string;
44
+ /**
45
+ * True iff at least one JUnit XML file was located AND parsed without throwing.
46
+ * Distinguishes "we have data and the test selector matched zero cases" (legit RUN-001 signal)
47
+ * from "we have no data because nothing parsed" (insufficient info — must stay silent).
48
+ */
49
+ parsedAny: boolean;
30
50
  }
31
51
  /**
32
52
  * Scan a Provar results directory for JUnit XML files and return structured step results.
@@ -12,6 +12,7 @@ import { XMLParser } from 'fast-xml-parser';
12
12
  import { assertPathAllowed, PathPolicyError } from '../security/pathPolicy.js';
13
13
  import { makeError, makeRequestId } from '../schemas/common.js';
14
14
  import { log } from '../logging/logger.js';
15
+ import { desc } from './descHelper.js';
15
16
  // ── Sub-schemas ───────────────────────────────────────────────────────────────
16
17
  const FilesetSchema = z.object({
17
18
  dir: z.string().describe('Directory path (relative or absolute) for the fileset'),
@@ -56,126 +57,141 @@ const AttachmentPropertiesSchema = z.object({
56
57
  export function registerAntGenerate(server, config) {
57
58
  server.registerTool('provar_ant_generate', {
58
59
  title: 'Generate ANT Build File',
59
- description: [
60
+ description: desc([
60
61
  'Generate a Provar ANT build.xml file.',
61
62
  'Produces the standard <project> skeleton with Provar-Compile and Run-Test-Case tasks.',
62
63
  'Supports targeting tests by project folder, plan folder, or specific .testcase files via filesets.',
63
64
  'Returns XML content. Writes to disk only when dry_run=false.',
64
- ].join(' '),
65
+ ].join(' '), 'Generate a Provar ANT build.xml with Provar-Compile and Run-Test-Case tasks.'),
65
66
  inputSchema: {
66
67
  // ── Core paths ──────────────────────────────────────────────────────────
67
68
  provar_home: z
68
69
  .string()
69
- .describe('Absolute path to the Provar installation directory (e.g. "C:/Program Files/Provar/"). Used for provar.home property and ant taskdef classpaths.'),
70
+ .describe(desc('Absolute path to the Provar installation directory (e.g. "C:/Program Files/Provar/"). Used for provar.home property and ant taskdef classpaths.', 'string, absolute path to Provar installation')),
70
71
  project_path: z
71
72
  .string()
72
73
  .default('..')
73
- .describe('Path to the Provar test project root. Defaults to ".." (parent of the ANT folder).'),
74
+ .describe(desc('Path to the Provar test project root. Defaults to ".." (parent of the ANT folder).', 'string, path to project root')),
74
75
  results_path: z
75
76
  .string()
76
77
  .default('../ANT/Results')
77
- .describe('Path where test results are written. Defaults to "../ANT/Results".'),
78
+ .describe(desc('Path where test results are written. Defaults to "../ANT/Results".', 'string, path for test results')),
78
79
  project_cache_path: z
79
80
  .string()
80
81
  .optional()
81
- .describe('Path to the .provarCaches directory. Defaults to "../../.provarCaches" relative to the ANT folder.'),
82
+ .describe(desc('Path to the .provarCaches directory. Defaults to "../../.provarCaches" relative to the ANT folder.', 'string, optional; path to .provarCaches')),
82
83
  license_path: z
83
84
  .string()
84
85
  .optional()
85
- .describe('Path to the Provar .licenses directory (e.g. "${env.PROVAR_HOME}/.licenses").'),
86
+ .describe(desc('Path to the Provar .licenses directory (e.g. "${env.PROVAR_HOME}/.licenses").', 'string, optional; path to .licenses dir')),
86
87
  smtp_path: z
87
88
  .string()
88
89
  .optional()
89
- .describe('Path to the Provar .smtp directory (e.g. "${env.PROVAR_HOME}/.smtp").'),
90
+ .describe(desc('Path to the Provar .smtp directory (e.g. "${env.PROVAR_HOME}/.smtp").', 'string, optional; path to .smtp dir')),
90
91
  // ── Test selection ──────────────────────────────────────────────────────
91
92
  filesets: z
92
93
  .array(FilesetSchema)
93
94
  .min(1)
94
- .describe('One or more filesets defining which tests to run. ' +
95
+ .describe(desc('One or more filesets defining which tests to run. ' +
95
96
  'To run all tests under a folder: { dir: "../tests" }. ' +
96
97
  'To run a plan: { id: "testplan", dir: "../plans/MyPlan" }. ' +
97
- 'To run specific test cases: { dir: "../tests/Suite", includes: ["MyTest.testcase"] }.'),
98
+ 'To run specific test cases: { dir: "../tests/Suite", includes: ["MyTest.testcase"] }.', 'array, min 1; filesets defining which tests to run')),
98
99
  // ── Browser / environment ───────────────────────────────────────────────
99
100
  web_browser: z
100
101
  .enum(['Chrome', 'Chrome_Headless', 'Firefox', 'Edge', 'Edge_Legacy', 'Safari', 'IE'])
101
102
  .default('Chrome')
102
- .describe('Web browser to use for test execution.'),
103
+ .describe(desc('Web browser to use for test execution.', 'enum Chrome|Chrome_Headless|Firefox|Edge|Safari|IE')),
103
104
  web_browser_configuration: z
104
105
  .string()
105
106
  .default('Full Screen')
106
- .describe('Browser window configuration (e.g. "Full Screen").'),
107
- web_browser_provider_name: z.string().default('Desktop').describe('Browser provider name (e.g. "Desktop").'),
107
+ .describe(desc('Browser window configuration (e.g. "Full Screen").', 'string, browser window config')),
108
+ web_browser_provider_name: z
109
+ .string()
110
+ .default('Desktop')
111
+ .describe(desc('Browser provider name (e.g. "Desktop").', 'string, browser provider name')),
108
112
  web_browser_device_name: z
109
113
  .string()
110
114
  .default('Full Screen')
111
- .describe('Browser device name (e.g. "Full Screen").'),
115
+ .describe(desc('Browser device name (e.g. "Full Screen").', 'string, browser device name')),
112
116
  test_environment: z
113
117
  .string()
114
118
  .default('')
115
- .describe('Named test environment to use (must match a connection in the project). Empty string uses default.'),
119
+ .describe(desc('Named test environment to use (must match a connection in the project). Empty string uses default.', 'string, optional; named test environment')),
116
120
  // ── Cache / metadata ────────────────────────────────────────────────────
117
121
  salesforce_metadata_cache: z
118
122
  .enum(['Reuse', 'Refresh', 'Reload'])
119
123
  .default('Reuse')
120
- .describe('Salesforce metadata cache strategy: Reuse (fastest, uses cached), Refresh (re-downloads), Reload (clears and re-downloads).'),
124
+ .describe(desc('Salesforce metadata cache strategy: Reuse (fastest, uses cached), Refresh (re-downloads), Reload (clears and re-downloads).', 'enum Reuse|Refresh|Reload')),
121
125
  // ── Output / logging ────────────────────────────────────────────────────
122
126
  results_path_disposition: z
123
127
  .enum(['Increment', 'Replace', 'Reuse'])
124
128
  .default('Increment')
125
- .describe('How to handle the results folder when it already exists: Increment (new subfolder), Replace (overwrite), Reuse (append).'),
129
+ .describe(desc('How to handle the results folder when it already exists: Increment (new subfolder), Replace (overwrite), Reuse (append).', 'enum Increment|Replace|Reuse')),
126
130
  test_output_level: z
127
131
  .enum(['BASIC', 'WARNING', 'DEBUG'])
128
132
  .default('BASIC')
129
- .describe('Verbosity level for test output logs.'),
133
+ .describe(desc('Verbosity level for test output logs.', 'enum BASIC|WARNING|DEBUG')),
130
134
  plugin_output_level: z
131
135
  .enum(['BASIC', 'WARNING', 'DEBUG'])
132
136
  .default('WARNING')
133
- .describe('Verbosity level for plugin output logs.'),
137
+ .describe(desc('Verbosity level for plugin output logs.', 'enum BASIC|WARNING|DEBUG')),
134
138
  // ── Execution behaviour ─────────────────────────────────────────────────
135
139
  stop_test_run_on_error: z
136
140
  .boolean()
137
141
  .default(false)
138
- .describe('Abort the entire test run when any test case fails.'),
142
+ .describe(desc('Abort the entire test run when any test case fails.', 'bool, optional; abort on failure')),
139
143
  exclude_callable_test_cases: z
140
144
  .boolean()
141
145
  .default(true)
142
- .describe('Skip test cases marked as callable (library/helper) when true.'),
146
+ .describe(desc('Skip test cases marked as callable (library/helper) when true.', 'bool, optional; skip callable tests')),
143
147
  dont_fail_build: z
144
148
  .boolean()
145
149
  .optional()
146
- .describe('When true, the ANT build does not fail even if tests fail. Useful for CI pipelines that collect results separately.'),
147
- invoke_test_run_monitor: z.boolean().default(true).describe('Enable the Provar test run monitor.'),
150
+ .describe(desc('When true, the ANT build does not fail even if tests fail. Useful for CI pipelines that collect results separately.', 'bool, optional; skip build failure on test fail')),
151
+ invoke_test_run_monitor: z
152
+ .boolean()
153
+ .default(true)
154
+ .describe(desc('Enable the Provar test run monitor.', 'bool, optional; enable test run monitor')),
148
155
  // ── Secrets / security ──────────────────────────────────────────────────
149
156
  secrets_password: z
150
157
  .string()
151
158
  .default('${env.ProvarSecretsPassword}')
152
- .describe('Encryption key used to decrypt the Provar .secrets file (the password string itself, not a file path). Defaults to reading from the ProvarSecretsPassword environment variable.'),
159
+ .describe(desc('Encryption key used to decrypt the Provar .secrets file (the password string itself, not a file path). Defaults to reading from the ProvarSecretsPassword environment variable.', 'string, NOT a file path; encryption key for .secrets')),
153
160
  test_environment_secrets_password: z
154
161
  .string()
155
162
  .optional()
156
- .describe('Per-environment secrets password. Defaults to reading from the ProvarSecretsPassword_EnvName environment variable.'),
163
+ .describe(desc('Per-environment secrets password. Defaults to reading from the ProvarSecretsPassword_EnvName environment variable.', 'string, optional; per-environment secrets key')),
157
164
  // ── Test Cycle ──────────────────────────────────────────────────────────
158
- test_cycle_path: z.string().optional().describe('Path to a TestCycle folder (used with test cycle reporting).'),
165
+ test_cycle_path: z
166
+ .string()
167
+ .optional()
168
+ .describe(desc('Path to a TestCycle folder (used with test cycle reporting).', 'string, optional; path to TestCycle folder')),
159
169
  test_cycle_run_type: z
160
170
  .enum(['ALL', 'FAILED', 'NEW'])
161
171
  .optional()
162
- .describe('Which tests in the cycle to run (ALL, FAILED, NEW).'),
172
+ .describe(desc('Which tests in the cycle to run (ALL, FAILED, NEW).', 'enum ALL|FAILED|NEW, optional')),
163
173
  // ── Plan features ───────────────────────────────────────────────────────
164
174
  plan_features: z
165
175
  .array(PlanFeatureSchema)
166
176
  .optional()
167
- .describe('Output and notification features to enable/disable (e.g. PDF, PIECHART, EMAIL). ' +
168
- 'Only meaningful when running by test plan.'),
177
+ .describe(desc('Output and notification features to enable/disable (e.g. PDF, PIECHART, EMAIL). ' +
178
+ 'Only meaningful when running by test plan.', 'array, optional; plan output/notification features')),
169
179
  // ── Email / attachment reporting ────────────────────────────────────────
170
- email_properties: EmailPropertiesSchema.optional().describe('Email notification settings. Omit to exclude <emailProperties> from the XML.'),
171
- attachment_properties: AttachmentPropertiesSchema.optional().describe('Attachment/report content settings. Omit to exclude <attachmentProperties> from the XML.'),
180
+ email_properties: EmailPropertiesSchema.optional().describe(desc('Email notification settings. Omit to exclude <emailProperties> from the XML.', 'object, optional; email notification settings')),
181
+ attachment_properties: AttachmentPropertiesSchema.optional().describe(desc('Attachment/report content settings. Omit to exclude <attachmentProperties> from the XML.', 'object, optional; attachment/report content settings')),
172
182
  // ── File output ─────────────────────────────────────────────────────────
173
183
  output_path: z
174
184
  .string()
175
185
  .optional()
176
- .describe('Where to write the build.xml file (returned in response). Required when dry_run=false.'),
177
- overwrite: z.boolean().default(false).describe('Overwrite output_path if the file already exists.'),
178
- dry_run: z.boolean().default(true).describe('true = return XML only (default); false = write to output_path.'),
186
+ .describe(desc('Where to write the build.xml file (returned in response). Required when dry_run=false.', 'string, optional; absolute path for build.xml output')),
187
+ overwrite: z
188
+ .boolean()
189
+ .default(false)
190
+ .describe(desc('Overwrite output_path if the file already exists.', 'bool, optional; overwrite if exists')),
191
+ dry_run: z
192
+ .boolean()
193
+ .default(true)
194
+ .describe(desc('true = return XML only (default); false = write to output_path.', 'bool, optional; true=return only, false=write')),
179
195
  },
180
196
  }, (input) => {
181
197
  const requestId = makeRequestId();
@@ -234,15 +250,21 @@ export function registerAntGenerate(server, config) {
234
250
  export function registerAntValidate(server, config) {
235
251
  server.registerTool('provar_ant_validate', {
236
252
  title: 'Validate ANT Build File',
237
- description: [
253
+ description: desc([
238
254
  'Validate a Provar ANT build.xml for structural correctness.',
239
255
  'Checks XML well-formedness, required <taskdef> declarations, <Provar-Compile> step,',
240
256
  '<Run-Test-Case> with required attributes (provarHome, projectPath, resultsPath),',
241
257
  'and at least one <fileset> child. Returns is_valid, issues list, and a validity_score.',
242
- ].join(' '),
258
+ ].join(' '), 'Validate a Provar ANT build.xml for structural correctness.'),
243
259
  inputSchema: {
244
- content: z.string().optional().describe('XML content to validate directly'),
245
- file_path: z.string().optional().describe('Path to the build.xml file to validate'),
260
+ content: z
261
+ .string()
262
+ .optional()
263
+ .describe(desc('XML content to validate directly', 'string, optional; inline XML')),
264
+ file_path: z
265
+ .string()
266
+ .optional()
267
+ .describe(desc('Path to the build.xml file to validate', 'string, optional; absolute path to build.xml')),
246
268
  },
247
269
  }, ({ content, file_path }) => {
248
270
  const requestId = makeRequestId();
@@ -642,6 +664,35 @@ function finalizeAnt(issues, provarHome, projectPath, resultsPath, webBrowser, t
642
664
  issues,
643
665
  };
644
666
  }
667
+ /**
668
+ * Classify a failure message into a coarse-grained category used for retry decisions.
669
+ * Mirrors the classifier in rcaTools.ts (PDX-490) so a downstream consumer sees the
670
+ * same labelling whether they consume `provar_automation_testrun.steps[]` or
671
+ * `provar_testrun_rca.failures[]`.
672
+ *
673
+ * Returns `undefined` when no pattern matches.
674
+ */
675
+ export function classifyStepErrorCategory(errorText) {
676
+ if (/Connection reset|Failed to read client socket message|socket hang up|ECONNRESET/i.test(errorText)) {
677
+ return 'INFRASTRUCTURE';
678
+ }
679
+ if (/NoSuchElementException/i.test(errorText))
680
+ return 'LOCATOR';
681
+ if (/TimeoutException/i.test(errorText))
682
+ return 'TIMEOUT';
683
+ if (/AssertionException/i.test(errorText))
684
+ return 'ASSERTION';
685
+ if (/SessionNotCreatedException|WebDriverException|ClassNotFoundException|LicenseException|InvalidPasswordException/i.test(errorText)) {
686
+ return 'OTHER';
687
+ }
688
+ return undefined;
689
+ }
690
+ /** Only transient categories (INFRASTRUCTURE, TIMEOUT) are retryable. */
691
+ export function isStepRetryable(category) {
692
+ if (category === undefined)
693
+ return undefined;
694
+ return category === 'INFRASTRUCTURE' || category === 'TIMEOUT';
695
+ }
645
696
  function extractFailureText(el) {
646
697
  if (!el)
647
698
  return undefined;
@@ -695,8 +746,15 @@ function extractStepsFromJUnit(parsed) {
695
746
  status = 'skip';
696
747
  const errorMessage = extractFailureText(tc['failure'] ?? tc['error']);
697
748
  const step = { testItemId: String(idx), title, status };
698
- if (errorMessage)
749
+ if (errorMessage) {
699
750
  step.errorMessage = errorMessage;
751
+ const error_category = classifyStepErrorCategory(errorMessage);
752
+ const retryable = isStepRetryable(error_category);
753
+ if (error_category !== undefined)
754
+ step.error_category = error_category;
755
+ if (retryable !== undefined)
756
+ step.retryable = retryable;
757
+ }
700
758
  steps.push(step);
701
759
  }
702
760
  }
@@ -722,13 +780,14 @@ function findXmlFiles(dir) {
722
780
  */
723
781
  export function parseJUnitResults(resultsDir) {
724
782
  if (!fs.existsSync(resultsDir)) {
725
- return { steps: [], warning: `Results directory not found: ${resultsDir}` };
783
+ return { steps: [], warning: `Results directory not found: ${resultsDir}`, parsedAny: false };
726
784
  }
727
785
  const xmlFiles = findXmlFiles(resultsDir);
728
786
  if (xmlFiles.length === 0) {
729
787
  return {
730
788
  steps: [],
731
789
  warning: 'No JUnit XML files found in results directory — structured step output unavailable.',
790
+ parsedAny: false,
732
791
  };
733
792
  }
734
793
  const parser = new XMLParser({
@@ -758,18 +817,23 @@ export function parseJUnitResults(resultsDir) {
758
817
  return {
759
818
  steps: [],
760
819
  warning: 'JUnit XML files found but could not be parsed — structured step output unavailable.',
820
+ parsedAny: false,
761
821
  };
762
822
  }
763
823
  if (allSteps.length === 0) {
824
+ // We did parse at least one file; the file just had zero <testcase> entries (or none we could
825
+ // recognise as steps). This is the legitimate "selector matched nothing" signal that RUN-001
826
+ // is built to catch.
764
827
  return {
765
828
  steps: [],
766
829
  warning: 'JUnit XML found but no test steps could be extracted — files may not be standard JUnit format.',
830
+ parsedAny: true,
767
831
  };
768
832
  }
769
833
  const warning = parseFailures > 0
770
834
  ? `${parseFailures} JUnit XML file(s) could not be parsed — step data may be incomplete.`
771
835
  : undefined;
772
- return { steps: allSteps, warning };
836
+ return { steps: allSteps, warning, parsedAny: true };
773
837
  }
774
838
  // ── Registration ──────────────────────────────────────────────────────────────
775
839
  export function registerAllAntTools(server, config) {