@provartesting/provardx-cli 1.5.0-dev.2 → 1.5.1

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 (147) hide show
  1. package/README.md +163 -12
  2. package/bin/mcp-start.js +74 -0
  3. package/lib/commands/provar/auth/clear.d.ts +7 -0
  4. package/lib/commands/provar/auth/clear.js +36 -0
  5. package/lib/commands/provar/auth/clear.js.map +1 -0
  6. package/lib/commands/provar/auth/login.d.ts +10 -0
  7. package/lib/commands/provar/auth/login.js +90 -0
  8. package/lib/commands/provar/auth/login.js.map +1 -0
  9. package/lib/commands/provar/auth/rotate.d.ts +7 -0
  10. package/lib/commands/provar/auth/rotate.js +42 -0
  11. package/lib/commands/provar/auth/rotate.js.map +1 -0
  12. package/lib/commands/provar/auth/status.d.ts +7 -0
  13. package/lib/commands/provar/auth/status.js +107 -0
  14. package/lib/commands/provar/auth/status.js.map +1 -0
  15. package/lib/commands/provar/mcp/start.d.ts +2 -0
  16. package/lib/commands/provar/mcp/start.js +14 -1
  17. package/lib/commands/provar/mcp/start.js.map +1 -1
  18. package/lib/mcp/docs/NITROX_CATALOG_SOURCE.json +6 -0
  19. package/lib/mcp/docs/NITROX_COMPONENT_CATALOG.md +2001 -0
  20. package/lib/mcp/docs/PROVAR_TEST_STEP_REFERENCE.md +1430 -0
  21. package/lib/mcp/docs/PROVAR_TOOL_GUIDE.md +187 -0
  22. package/lib/mcp/licensing/algasClient.js +14 -5
  23. package/lib/mcp/licensing/algasClient.js.map +1 -1
  24. package/lib/mcp/licensing/ideDetection.d.ts +0 -12
  25. package/lib/mcp/licensing/ideDetection.js +1 -73
  26. package/lib/mcp/licensing/ideDetection.js.map +1 -1
  27. package/lib/mcp/licensing/licenseCache.js +7 -1
  28. package/lib/mcp/licensing/licenseCache.js.map +1 -1
  29. package/lib/mcp/licensing/licenseValidator.d.ts +3 -3
  30. package/lib/mcp/licensing/licenseValidator.js +11 -4
  31. package/lib/mcp/licensing/licenseValidator.js.map +1 -1
  32. package/lib/mcp/prompts/guidePrompts.d.ts +4 -0
  33. package/lib/mcp/prompts/guidePrompts.js +334 -0
  34. package/lib/mcp/prompts/guidePrompts.js.map +1 -0
  35. package/lib/mcp/prompts/index.d.ts +2 -0
  36. package/lib/mcp/prompts/index.js +23 -0
  37. package/lib/mcp/prompts/index.js.map +1 -0
  38. package/lib/mcp/prompts/loopPrompts.d.ts +6 -0
  39. package/lib/mcp/prompts/loopPrompts.js +435 -0
  40. package/lib/mcp/prompts/loopPrompts.js.map +1 -0
  41. package/lib/mcp/prompts/migrationPrompts.d.ts +4 -0
  42. package/lib/mcp/prompts/migrationPrompts.js +207 -0
  43. package/lib/mcp/prompts/migrationPrompts.js.map +1 -0
  44. package/lib/mcp/rules/provar_best_practices_rules.json +256 -544
  45. package/lib/mcp/security/pathPolicy.d.ts +5 -0
  46. package/lib/mcp/security/pathPolicy.js +58 -3
  47. package/lib/mcp/security/pathPolicy.js.map +1 -1
  48. package/lib/mcp/server.d.ts +18 -0
  49. package/lib/mcp/server.js +232 -19
  50. package/lib/mcp/server.js.map +1 -1
  51. package/lib/mcp/tools/antTools.d.ts +15 -0
  52. package/lib/mcp/tools/antTools.js +369 -170
  53. package/lib/mcp/tools/antTools.js.map +1 -1
  54. package/lib/mcp/tools/automationTools.d.ts +18 -8
  55. package/lib/mcp/tools/automationTools.js +333 -176
  56. package/lib/mcp/tools/automationTools.js.map +1 -1
  57. package/lib/mcp/tools/bestPracticesEngine.js +161 -23
  58. package/lib/mcp/tools/bestPracticesEngine.js.map +1 -1
  59. package/lib/mcp/tools/connectionTools.d.ts +4 -0
  60. package/lib/mcp/tools/connectionTools.js +242 -0
  61. package/lib/mcp/tools/connectionTools.js.map +1 -0
  62. package/lib/mcp/tools/defectTools.d.ts +1 -1
  63. package/lib/mcp/tools/defectTools.js +61 -50
  64. package/lib/mcp/tools/defectTools.js.map +1 -1
  65. package/lib/mcp/tools/descHelper.d.ts +5 -0
  66. package/lib/mcp/tools/descHelper.js +14 -0
  67. package/lib/mcp/tools/descHelper.js.map +1 -0
  68. package/lib/mcp/tools/hierarchyValidate.d.ts +1 -1
  69. package/lib/mcp/tools/hierarchyValidate.js +127 -42
  70. package/lib/mcp/tools/hierarchyValidate.js.map +1 -1
  71. package/lib/mcp/tools/nitroXTools.d.ts +23 -0
  72. package/lib/mcp/tools/nitroXTools.js +863 -0
  73. package/lib/mcp/tools/nitroXTools.js.map +1 -0
  74. package/lib/mcp/tools/pageObjectGenerate.js +150 -57
  75. package/lib/mcp/tools/pageObjectGenerate.js.map +1 -1
  76. package/lib/mcp/tools/pageObjectValidate.js +143 -46
  77. package/lib/mcp/tools/pageObjectValidate.js.map +1 -1
  78. package/lib/mcp/tools/projectInspect.js +79 -32
  79. package/lib/mcp/tools/projectInspect.js.map +1 -1
  80. package/lib/mcp/tools/projectValidateFromPath.js +185 -58
  81. package/lib/mcp/tools/projectValidateFromPath.js.map +1 -1
  82. package/lib/mcp/tools/propertiesTools.d.ts +2 -0
  83. package/lib/mcp/tools/propertiesTools.js +358 -78
  84. package/lib/mcp/tools/propertiesTools.js.map +1 -1
  85. package/lib/mcp/tools/qualityHubApiTools.d.ts +3 -0
  86. package/lib/mcp/tools/qualityHubApiTools.js +139 -0
  87. package/lib/mcp/tools/qualityHubApiTools.js.map +1 -0
  88. package/lib/mcp/tools/qualityHubTools.js +292 -72
  89. package/lib/mcp/tools/qualityHubTools.js.map +1 -1
  90. package/lib/mcp/tools/rcaTools.d.ts +3 -2
  91. package/lib/mcp/tools/rcaTools.js +194 -56
  92. package/lib/mcp/tools/rcaTools.js.map +1 -1
  93. package/lib/mcp/tools/sfSpawn.d.ts +25 -3
  94. package/lib/mcp/tools/sfSpawn.js +154 -6
  95. package/lib/mcp/tools/sfSpawn.js.map +1 -1
  96. package/lib/mcp/tools/testCaseGenerate.js +285 -78
  97. package/lib/mcp/tools/testCaseGenerate.js.map +1 -1
  98. package/lib/mcp/tools/testCaseStepTools.d.ts +4 -0
  99. package/lib/mcp/tools/testCaseStepTools.js +244 -0
  100. package/lib/mcp/tools/testCaseStepTools.js.map +1 -0
  101. package/lib/mcp/tools/testCaseValidate.d.ts +11 -0
  102. package/lib/mcp/tools/testCaseValidate.js +381 -46
  103. package/lib/mcp/tools/testCaseValidate.js.map +1 -1
  104. package/lib/mcp/tools/testPlanTools.d.ts +1 -0
  105. package/lib/mcp/tools/testPlanTools.js +316 -59
  106. package/lib/mcp/tools/testPlanTools.js.map +1 -1
  107. package/lib/mcp/tools/testPlanValidate.js +114 -23
  108. package/lib/mcp/tools/testPlanValidate.js.map +1 -1
  109. package/lib/mcp/tools/testSuiteValidate.js +130 -15
  110. package/lib/mcp/tools/testSuiteValidate.js.map +1 -1
  111. package/lib/mcp/update/updateChecker.d.ts +14 -0
  112. package/lib/mcp/update/updateChecker.js +228 -0
  113. package/lib/mcp/update/updateChecker.js.map +1 -0
  114. package/lib/mcp/utils/detailLevel.d.ts +9 -0
  115. package/lib/mcp/utils/detailLevel.js +20 -0
  116. package/lib/mcp/utils/detailLevel.js.map +1 -0
  117. package/lib/mcp/utils/fieldMask.d.ts +17 -0
  118. package/lib/mcp/utils/fieldMask.js +75 -0
  119. package/lib/mcp/utils/fieldMask.js.map +1 -0
  120. package/lib/mcp/utils/tokenMeta.d.ts +40 -0
  121. package/lib/mcp/utils/tokenMeta.js +90 -0
  122. package/lib/mcp/utils/tokenMeta.js.map +1 -0
  123. package/lib/mcp/utils/validationDiff.d.ts +57 -0
  124. package/lib/mcp/utils/validationDiff.js +191 -0
  125. package/lib/mcp/utils/validationDiff.js.map +1 -0
  126. package/lib/mcp/utils/validationScore.d.ts +15 -0
  127. package/lib/mcp/utils/validationScore.js +31 -0
  128. package/lib/mcp/utils/validationScore.js.map +1 -0
  129. package/lib/services/auth/credentials.d.ts +21 -0
  130. package/lib/services/auth/credentials.js +75 -0
  131. package/lib/services/auth/credentials.js.map +1 -0
  132. package/lib/services/auth/loginFlow.d.ts +68 -0
  133. package/lib/services/auth/loginFlow.js +216 -0
  134. package/lib/services/auth/loginFlow.js.map +1 -0
  135. package/lib/services/projectValidation.d.ts +5 -2
  136. package/lib/services/projectValidation.js +83 -31
  137. package/lib/services/projectValidation.js.map +1 -1
  138. package/lib/services/qualityHub/client.d.ts +161 -0
  139. package/lib/services/qualityHub/client.js +226 -0
  140. package/lib/services/qualityHub/client.js.map +1 -0
  141. package/messages/sf.provar.auth.clear.md +16 -0
  142. package/messages/sf.provar.auth.login.md +31 -0
  143. package/messages/sf.provar.auth.rotate.md +23 -0
  144. package/messages/sf.provar.auth.status.md +16 -0
  145. package/messages/sf.provar.mcp.start.md +83 -48
  146. package/oclif.manifest.json +325 -28
  147. package/package.json +35 -12
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Version](https://img.shields.io/npm/v/@provartesting/provardx-cli.svg)](https://npmjs.org/package/@provartesting/provardx-cli)
4
4
  [![Downloads/week](https://img.shields.io/npm/dw/@provartesting/provardx-cli.svg)](https://npmjs.org/package/@provartesting/provardx-cli)
5
5
  [![License](https://img.shields.io/npm/l/@provartesting/provardx-cli.svg)](https://github.com/ProvarTesting/provardx-cli/blob/main/LICENSE.md)
6
+ [![Get Access](https://img.shields.io/badge/Quality%20Hub%20API-Get%20Access-blue)](https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access)
6
7
 
7
8
  # What is the ProvarDX CLI?
8
9
 
@@ -10,6 +11,8 @@ The Provar DX CLI is a Salesforce CLI plugin for Provar customers who want to au
10
11
 
11
12
  # Installation, Update, and Uninstall
12
13
 
14
+ **Requires Node.js 18–24 (LTS 22 recommended).** Node 25+ is not yet supported due to a breaking change in a transitive dependency. Check with `node --version`.
15
+
13
16
  Install the plugin
14
17
 
15
18
  ```sh-session
@@ -30,33 +33,83 @@ $ sf plugins uninstall @provartesting/provardx-cli
30
33
 
31
34
  # MCP Server (AI-Assisted Quality)
32
35
 
33
- The Provar DX CLI includes a built-in **Model Context Protocol (MCP) server** that connects AI assistants (Claude Desktop, Claude Code, Cursor) directly to your Provar project. Once connected, an AI agent can inspect your project structure, generate Page Objects and test cases, and validate every level of the test hierarchy with quality scores that match the Provar Quality Hub API.
36
+ The Provar DX CLI includes a built-in **Model Context Protocol (MCP) server** that connects AI assistants (Claude Desktop, Claude Code, Cursor) directly to your Provar project. Once connected, an AI agent can inspect your project structure, generate Page Objects and test cases, validate every level of the test hierarchy with quality scores, and work with NitroX (Hybrid Model) component page objects for LWC, Screen Flow, Industry Components, Experience Cloud, and HTML5.
37
+
38
+ Validation runs in two modes: **local only** (structural rules, no key required) or **Quality Hub API** (170+ rules, quality scoring — requires a `pv_k_` API key). Don't have an account? **[Request access](https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access)**.
39
+
40
+ ## Quick setup
41
+
42
+ **Requires:** Provar Automation IDE installed with an activated license. Node.js 18–24 must be on your PATH.
43
+
44
+ ### Option A — Zero-install (recommended for Claude Desktop)
45
+
46
+ No prior setup needed. Paste this into your Claude Desktop config file and restart the app:
47
+
48
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
49
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "provar": {
55
+ "command": "npx",
56
+ "args": ["-y", "@provartesting/provardx-cli", "mcp", "start", "--allowed-paths", "/path/to/your/provar/project"]
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ `npx -y` downloads the package automatically on first use — no `sf` or separate install step required.
63
+
64
+ **Claude Code** — run once to register the server:
34
65
 
35
66
  ```sh
36
- sf provar mcp start --allowed-paths /path/to/your/provar/project
67
+ claude mcp add provar -s user -- npx -y @provartesting/provardx-cli mcp start --allowed-paths /path/to/your/provar/project
37
68
  ```
38
69
 
39
- 📖 **See [docs/mcp.md](https://github.com/ProvarTesting/provardx-cli/blob/main/docs/mcp.md) for full setup and tool documentation.**
70
+ ### Option B Global sf plugin install
40
71
 
41
- ## License Validation
72
+ Prefer a persistent global install? Install once, then use the `sf` command:
42
73
 
43
- The MCP server verifies your Provar license before accepting any connections. Validation is automatic — no extra flags are required for standard usage.
74
+ ```sh
75
+ # 1. Install the plugin
76
+ sf plugins install @provartesting/provardx-cli
44
77
 
45
- **How it works:**
78
+ # 2. (Optional) Authenticate for full 170+ rule validation
79
+ sf provar auth login
80
+ ```
46
81
 
47
- 1. **Auto-detection** the server reads `~/Provar/.licenses/*.properties` (the same files written by Provar's IDE plugins). If a valid, activated license is found the server starts immediately.
48
- 2. **Cache** — successful validations are cached at `~/Provar/.licenses/.mcp-license-cache.json` (2 h TTL). Subsequent starts within the TTL window skip the disk scan.
49
- 3. **Grace fallback** — if the IDE license files cannot be found or read and the cache is stale (but ≤ 48 h old), the server starts with a warning on stderr using the cached result so CI pipelines are not broken by transient local file-access issues.
50
- 4. **Fail closed** — if no valid license is detected the command exits with a non-zero exit code and a clear error message.
82
+ **Claude Desktop** config using the global install:
51
83
 
52
- **`NODE_ENV=test` fast-path:**
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "provar": {
88
+ "command": "sf",
89
+ "args": ["provar", "mcp", "start", "--allowed-paths", "/path/to/your/provar/project"]
90
+ }
91
+ }
92
+ }
93
+ ```
53
94
 
54
- When `NODE_ENV=test` the validation step is skipped entirely. This is intended only for the plugin's own unit-test suite.
95
+ > **Windows (Claude Desktop):** Use `sf.cmd` instead of `sf` if the server fails to start.
96
+
97
+ **Claude Code** using the global install:
98
+
99
+ ```sh
100
+ claude mcp add provar -s user -- sf provar mcp start --allowed-paths /path/to/your/provar/project
101
+ ```
102
+
103
+ 📖 **[docs/mcp.md](https://github.com/ProvarTesting/provardx-cli/blob/main/docs/mcp.md) — full setup, all 35+ tools, 11 MCP prompts, troubleshooting.**
55
104
 
56
105
  ---
57
106
 
58
107
  # Commands
59
108
 
109
+ - [`sf provar auth login`](#sf-provar-auth-login)
110
+ - [`sf provar auth rotate`](#sf-provar-auth-rotate)
111
+ - [`sf provar auth status`](#sf-provar-auth-status)
112
+ - [`sf provar auth clear`](#sf-provar-auth-clear)
60
113
  - [`sf provar mcp start`](#sf-provar-mcp-start)
61
114
  - [`sf provar config get`](#sf-provar-config-get)
62
115
  - [`sf provar config set`](#sf-provar-config-set)
@@ -84,6 +137,99 @@ When `NODE_ENV=test` the validation step is skipped entirely. This is intended o
84
137
  - [`sf provar manager test run report`](#sf-provar-manager-test-run-report) _(deprecated — use `sf provar quality-hub test run report`)_
85
138
  - [`sf provar manager test run abort`](#sf-provar-manager-test-run-abort) _(deprecated — use `sf provar quality-hub test run abort`)_
86
139
 
140
+ ## `sf provar auth login`
141
+
142
+ Log in to Provar Quality Hub and store your API key.
143
+
144
+ ```
145
+ USAGE
146
+ $ sf provar auth login [--url <value>]
147
+
148
+ FLAGS
149
+ --url=<value> Override the Quality Hub API base URL (for non-production environments).
150
+
151
+ DESCRIPTION
152
+ Opens a browser to the Provar login page. After you authenticate, your API key is
153
+ stored at ~/.provar/credentials.json and used automatically by the Provar MCP tools
154
+ and CI/CD integrations. The key is valid for approximately 90 days.
155
+
156
+ For CI/CD pipelines (GitHub Actions, Jenkins, etc.) where a browser cannot open:
157
+ run sf provar auth login once on your local machine, copy the api_key value from
158
+ ~/.provar/credentials.json, and store it as the PROVAR_API_KEY environment variable
159
+ or secret in your pipeline. Rotate the secret every ~90 days when the key expires.
160
+
161
+ Don't have an account? Request access at:
162
+ https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access
163
+
164
+ EXAMPLES
165
+ Log in interactively:
166
+
167
+ $ sf provar auth login
168
+
169
+ Log in against a staging environment:
170
+
171
+ $ sf provar auth login --url https://dev.api.example.com
172
+ ```
173
+
174
+ ## `sf provar auth rotate`
175
+
176
+ Rotate your stored API key without re-authenticating via browser.
177
+
178
+ ```
179
+ USAGE
180
+ $ sf provar auth rotate
181
+
182
+ DESCRIPTION
183
+ Exchanges your current pv_k_ key for a new one atomically. The old key is
184
+ invalidated immediately. The new key is written to ~/.provar/credentials.json.
185
+
186
+ Use this to rotate your key on a regular schedule (~every 90 days) without
187
+ going through the browser login flow. If your current key is already expired,
188
+ run sf provar auth login instead.
189
+
190
+ EXAMPLES
191
+ Rotate the stored API key:
192
+
193
+ $ sf provar auth rotate
194
+ ```
195
+
196
+ ## `sf provar auth status`
197
+
198
+ Show the current API key configuration and validate it against Quality Hub.
199
+
200
+ ```
201
+ USAGE
202
+ $ sf provar auth status
203
+
204
+ DESCRIPTION
205
+ Reports whether an API key is configured, where it came from (environment variable
206
+ or credentials file), and performs a live check against the Quality Hub API to
207
+ confirm the key is still valid.
208
+
209
+ EXAMPLES
210
+ Check auth status:
211
+
212
+ $ sf provar auth status
213
+ ```
214
+
215
+ ## `sf provar auth clear`
216
+
217
+ Remove the stored API key.
218
+
219
+ ```
220
+ USAGE
221
+ $ sf provar auth clear
222
+
223
+ DESCRIPTION
224
+ Deletes ~/.provar/credentials.json and revokes the key server-side. After clearing,
225
+ the MCP tools fall back to local validation mode. Has no effect if no key is stored.
226
+
227
+ EXAMPLES
228
+ Remove the stored key:
229
+
230
+ $ sf provar auth clear
231
+ ```
232
+
87
233
  ## `sf provar mcp start`
88
234
 
89
235
  Start a local MCP server for Provar tools over stdio transport.
@@ -136,6 +282,11 @@ TOOLS EXPOSED
136
282
  provar.testplan.add-instance — wire a test case into a plan suite by writing a .testinstance file
137
283
  provar.testplan.create-suite — create a new test suite directory with .planitem inside a plan
138
284
  provar.testplan.remove-instance — remove a .testinstance file from a plan suite
285
+ provar.nitrox.discover — discover projects containing NitroX (Hybrid Model) page objects
286
+ provar.nitrox.read — read NitroX .po.json files and return parsed content
287
+ provar.nitrox.validate — validate a NitroX .po.json against schema rules
288
+ provar.nitrox.generate — generate a new NitroX .po.json from a component description
289
+ provar.nitrox.patch — apply a JSON merge-patch to an existing NitroX .po.json file
139
290
 
140
291
  EXAMPLES
141
292
  Start MCP server (accepts stdio connections from Claude Desktop / Cursor):
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ // Lightweight zero-install entrypoint for the Provar MCP server.
3
+ // Usage: npx -y @provartesting/provardx-cli@beta mcp start --allowed-paths /path/to/project
4
+
5
+ const args = process.argv.slice(2);
6
+
7
+ if (args[0] !== 'mcp' || args[1] !== 'start') {
8
+ process.stderr.write(
9
+ 'Usage: provardx mcp start --allowed-paths <path> [--auto-defects] [--auto-update] [--no-update-check]\n'
10
+ );
11
+ process.exit(1);
12
+ }
13
+
14
+ const remaining = args.slice(2);
15
+ /** @type {string[]} */
16
+ const allowedPaths = [];
17
+ let autoDefects = false;
18
+ let autoUpdate = false;
19
+ let noUpdateCheck = false;
20
+
21
+ for (let i = 0; i < remaining.length; i++) {
22
+ const arg = remaining[i];
23
+ if (arg === '--allowed-paths' || arg === '-a') {
24
+ if (i + 1 >= remaining.length) {
25
+ process.stderr.write('[provar-mcp] Error: --allowed-paths requires a path value.\n');
26
+ process.exit(1);
27
+ }
28
+ allowedPaths.push(remaining[++i]);
29
+ } else if (arg.startsWith('--allowed-paths=')) {
30
+ allowedPaths.push(arg.slice('--allowed-paths='.length));
31
+ } else if (arg === '--auto-defects') {
32
+ autoDefects = true;
33
+ } else if (arg === '--auto-update') {
34
+ autoUpdate = true;
35
+ } else if (arg === '--no-update-check') {
36
+ noUpdateCheck = true;
37
+ }
38
+ }
39
+
40
+ if (allowedPaths.length === 0) {
41
+ process.stderr.write(
42
+ '[provar-mcp] Error: --allowed-paths is required.\n' +
43
+ 'Example: npx -y @provartesting/provardx-cli@beta mcp start --allowed-paths /path/to/project\n'
44
+ );
45
+ process.exit(1);
46
+ }
47
+
48
+ if (autoDefects) {
49
+ process.env['PROVAR_AUTO_DEFECTS'] = '1';
50
+ }
51
+
52
+ // Dynamic imports placed after arg validation so early-exit paths need no compiled lib.
53
+ const { validateLicense, LicenseError } = await import('../lib/mcp/licensing/index.js');
54
+ const { checkForUpdate } = await import('../lib/mcp/update/updateChecker.js');
55
+ const { createProvarMcpServer } = await import('../lib/mcp/server.js');
56
+ const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
57
+
58
+ try {
59
+ const result = await validateLicense();
60
+ if (result.offlineGrace) {
61
+ process.stderr.write('[provar-mcp] Warning: license validated from offline cache (last checked > 2h ago).\n');
62
+ }
63
+ } catch (err) {
64
+ if (err instanceof LicenseError) {
65
+ process.stderr.write(`[provar-mcp] Error: ${/** @type {Error} */ (err).message}\n`);
66
+ process.exit(1);
67
+ }
68
+ throw err;
69
+ }
70
+
71
+ const updateResult = await checkForUpdate({ noUpdateCheck, autoUpdate });
72
+ const server = createProvarMcpServer({ allowedPaths, updateResult });
73
+ const transport = new StdioServerTransport();
74
+ await server.connect(transport);
@@ -0,0 +1,7 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export default class SfProvarAuthClear extends SfCommand<void> {
3
+ static readonly summary: string;
4
+ static readonly description: string;
5
+ static readonly examples: string[];
6
+ run(): Promise<void>;
7
+ }
@@ -0,0 +1,36 @@
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 { SfCommand } from '@salesforce/sf-plugins-core';
8
+ import { Messages } from '@provartesting/provardx-plugins-utils';
9
+ import { clearCredentials, readStoredCredentials } from '../../../services/auth/credentials.js';
10
+ import { qualityHubClient, getQualityHubBaseUrl } from '../../../services/qualityHub/client.js';
11
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
12
+ const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.clear');
13
+ export default class SfProvarAuthClear extends SfCommand {
14
+ static summary = messages.getMessage('summary');
15
+ static description = messages.getMessage('description');
16
+ static examples = messages.getMessages('examples');
17
+ async run() {
18
+ const stored = readStoredCredentials();
19
+ if (stored) {
20
+ const baseUrl = getQualityHubBaseUrl();
21
+ try {
22
+ await qualityHubClient.revokeKey(stored.api_key, baseUrl);
23
+ }
24
+ catch {
25
+ this.log(' Note: could not reach Quality Hub to revoke key server-side (offline?).');
26
+ this.log(' The local credentials have been removed — the key may still be valid until it expires.');
27
+ }
28
+ }
29
+ clearCredentials();
30
+ this.log('API key cleared.');
31
+ this.log(' Next validation will use local rules only (structural checks, no quality scoring).');
32
+ this.log(' To reconfigure: sf provar auth login');
33
+ this.log(' For CI/CD: set the PROVAR_API_KEY environment variable.');
34
+ }
35
+ }
36
+ //# sourceMappingURL=clear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/clear.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAEhG,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,sBAAsB,CAAC,CAAC;AAE9F,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,SAAe;IACrD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5D,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;gBACtF,IAAI,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;YACvG,CAAC;QACH,CAAC;QAED,gBAAgB,EAAE,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC;QACjG,IAAI,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC7E,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export default class SfProvarAuthLogin extends SfCommand<void> {
3
+ static readonly summary: string;
4
+ static readonly description: string;
5
+ static readonly examples: string[];
6
+ static readonly flags: {
7
+ url: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,90 @@
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 { Flags, SfCommand } from '@salesforce/sf-plugins-core';
9
+ import { Messages } from '@provartesting/provardx-plugins-utils';
10
+ import { writeCredentials } from '../../../services/auth/credentials.js';
11
+ import { loginFlowClient } from '../../../services/auth/loginFlow.js';
12
+ import { qualityHubClient, getQualityHubBaseUrl, QualityHubAuthError, REQUEST_ACCESS_URL, } from '../../../services/qualityHub/client.js';
13
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
14
+ const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.login');
15
+ // Production values bundled at auth handoff (2026-04-11).
16
+ // Override via PROVAR_COGNITO_DOMAIN / PROVAR_COGNITO_CLIENT_ID for non-prod environments.
17
+ const DEFAULT_COGNITO_DOMAIN = 'us-east-1xpfwzwmop.auth.us-east-1.amazoncognito.com';
18
+ const DEFAULT_CLIENT_ID = '29cs1a784r4cervmth8ugbkkri';
19
+ export default class SfProvarAuthLogin extends SfCommand {
20
+ static summary = messages.getMessage('summary');
21
+ static description = messages.getMessage('description');
22
+ static examples = messages.getMessages('examples');
23
+ static flags = {
24
+ url: Flags.string({
25
+ summary: messages.getMessage('flags.url.summary'),
26
+ required: false,
27
+ }),
28
+ };
29
+ async run() {
30
+ const { flags } = await this.parse(SfProvarAuthLogin);
31
+ const cognitoDomain = process.env.PROVAR_COGNITO_DOMAIN ?? DEFAULT_COGNITO_DOMAIN;
32
+ const clientId = process.env.PROVAR_COGNITO_CLIENT_ID ?? DEFAULT_CLIENT_ID;
33
+ const baseUrl = flags.url ?? getQualityHubBaseUrl();
34
+ // ── Step 1: Generate PKCE pair, nonce, and state ───────────────────────
35
+ const { verifier, challenge } = loginFlowClient.generatePkce();
36
+ const nonce = loginFlowClient.generateNonce();
37
+ const state = loginFlowClient.generateState();
38
+ // ── Step 2: Find an available registered callback port ──────────────────
39
+ const port = await loginFlowClient.findAvailablePort();
40
+ const redirectUri = `http://localhost:${port}/callback`;
41
+ // ── Step 3: Build the Cognito authorize URL ────────────────────────────
42
+ const authorizeUrl = new URL(`https://${cognitoDomain}/oauth2/authorize`);
43
+ authorizeUrl.searchParams.set('response_type', 'code');
44
+ authorizeUrl.searchParams.set('client_id', clientId);
45
+ authorizeUrl.searchParams.set('redirect_uri', redirectUri);
46
+ authorizeUrl.searchParams.set('code_challenge', challenge);
47
+ authorizeUrl.searchParams.set('code_challenge_method', 'S256');
48
+ authorizeUrl.searchParams.set('scope', 'openid email aws.cognito.signin.user.admin');
49
+ authorizeUrl.searchParams.set('state', state);
50
+ authorizeUrl.searchParams.set('nonce', nonce);
51
+ // ── Step 4: Open browser and wait for callback ──────────────────────────
52
+ this.log('Opening browser for login...');
53
+ this.log(` If the browser did not open, visit:\n ${authorizeUrl.toString()}`);
54
+ loginFlowClient.openBrowser(authorizeUrl.toString());
55
+ this.log('\nWaiting for authentication... (Ctrl-C to cancel)');
56
+ const authCode = await loginFlowClient.listenForCallback(port, state);
57
+ // ── Step 5: Exchange code for Cognito tokens ────────────────────────────
58
+ const tokens = await loginFlowClient.exchangeCodeForTokens({
59
+ code: authCode,
60
+ redirectUri,
61
+ clientId,
62
+ verifier,
63
+ tokenEndpoint: `https://${cognitoDomain}/oauth2/token`,
64
+ });
65
+ // ── Step 6: Exchange Cognito access token for pv_k_ key ─────────────────
66
+ // Cognito tokens are held in memory only — discarded after this call.
67
+ let keyData;
68
+ try {
69
+ keyData = await qualityHubClient.exchangeTokenForKey(tokens.access_token, baseUrl);
70
+ }
71
+ catch (err) {
72
+ if (err instanceof QualityHubAuthError) {
73
+ this.error(`No Provar MCP account found for this login.\nRequest access at: ${REQUEST_ACCESS_URL}`, {
74
+ exit: 1,
75
+ });
76
+ }
77
+ throw err;
78
+ }
79
+ // ── Step 7: Persist the pv_k_ key ──────────────────────────────────────
80
+ writeCredentials(keyData.api_key, keyData.prefix, 'cognito', {
81
+ username: keyData.username,
82
+ tier: keyData.tier,
83
+ expires_at: keyData.expires_at,
84
+ });
85
+ this.log(`\nAuthenticated as ${keyData.username} (${keyData.tier} tier)`);
86
+ this.log(`API key stored (prefix: ${keyData.prefix}). Valid until ${keyData.expires_at}.`);
87
+ this.log(" Run 'sf provar auth status' to check at any time.");
88
+ }
89
+ }
90
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/login.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,wCAAwC,CAAC;AAEhD,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,sBAAsB,CAAC,CAAC;AAE9F,0DAA0D;AAC1D,2FAA2F;AAC3F,MAAM,sBAAsB,GAAG,qDAAqD,CAAC;AACrF,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,SAAe;IACrD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,CAAU,KAAK,GAAG;QAC7B,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,mBAAmB,CAAC;YACjD,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAEtD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,sBAAsB,CAAC;QAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,iBAAiB,CAAC;QAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAEpD,0EAA0E;QAC1E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC,YAAY,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;QAE9C,2EAA2E;QAC3E,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,iBAAiB,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,oBAAoB,IAAI,WAAW,CAAC;QAExD,0EAA0E;QAC1E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,WAAW,aAAa,mBAAmB,CAAC,CAAC;QAC1E,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACvD,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACrD,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAC3D,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;QAC3D,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;QAC/D,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,4CAA4C,CAAC,CAAC;QACrF,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9C,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE9C,2EAA2E;QAC3E,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,4CAA4C,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAChF,eAAe,CAAC,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;QAErD,IAAI,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEtE,2EAA2E;QAC3E,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,qBAAqB,CAAC;YACzD,IAAI,EAAE,QAAQ;YACd,WAAW;YACX,QAAQ;YACR,QAAQ;YACR,aAAa,EAAE,WAAW,aAAa,eAAe;SACvD,CAAC,CAAC;QAEH,2EAA2E;QAC3E,sEAAsE;QACtE,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,gBAAgB,CAAC,mBAAmB,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACrF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CAAC,mEAAmE,kBAAkB,EAAE,EAAE;oBAClG,IAAI,EAAE,CAAC;iBACR,CAAC,CAAC;YACL,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,0EAA0E;QAC1E,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;YAC3D,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,QAAQ,CAAC,CAAC;QAC1E,IAAI,CAAC,GAAG,CAAC,2BAA2B,OAAO,CAAC,MAAM,kBAAkB,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC;QAC3F,IAAI,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IAClE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export default class SfProvarAuthRotate extends SfCommand<void> {
3
+ static readonly summary: string;
4
+ static readonly description: string;
5
+ static readonly examples: string[];
6
+ run(): Promise<void>;
7
+ }
@@ -0,0 +1,42 @@
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 { SfCommand } from '@salesforce/sf-plugins-core';
9
+ import { Messages } from '@provartesting/provardx-plugins-utils';
10
+ import { readStoredCredentials, writeCredentials } from '../../../services/auth/credentials.js';
11
+ import { qualityHubClient, getQualityHubBaseUrl, QualityHubAuthError } from '../../../services/qualityHub/client.js';
12
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
13
+ const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.rotate');
14
+ export default class SfProvarAuthRotate extends SfCommand {
15
+ static summary = messages.getMessage('summary');
16
+ static description = messages.getMessage('description');
17
+ static examples = messages.getMessages('examples');
18
+ async run() {
19
+ const stored = readStoredCredentials();
20
+ if (!stored) {
21
+ this.error('No API key stored. Run `sf provar auth login` first.', { exit: 1 });
22
+ }
23
+ const baseUrl = getQualityHubBaseUrl();
24
+ try {
25
+ const keyData = await qualityHubClient.rotateKey(stored.api_key, baseUrl);
26
+ writeCredentials(keyData.api_key, keyData.prefix, 'cognito', {
27
+ username: keyData.username,
28
+ tier: keyData.tier,
29
+ expires_at: keyData.expires_at,
30
+ });
31
+ this.log(`API key rotated (new prefix: ${keyData.prefix}). Valid until ${keyData.expires_at}.`);
32
+ this.log(" Run 'sf provar auth status' to verify.");
33
+ }
34
+ catch (err) {
35
+ if (err instanceof QualityHubAuthError) {
36
+ this.error('Current key is invalid or expired — rotation requires a valid key.\nRun `sf provar auth login` to authenticate via browser and get a fresh key.', { exit: 1 });
37
+ }
38
+ throw err;
39
+ }
40
+ }
41
+ }
42
+ //# sourceMappingURL=rotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/rotate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAErH,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,uBAAuB,CAAC,CAAC;AAE/F,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,SAAe;IACtD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;QAEvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,sDAAsD,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;QAEvC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC1E,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;gBAC3D,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,gCAAgC,OAAO,CAAC,MAAM,kBAAkB,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC;YAChG,IAAI,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CACR,iJAAiJ,EACjJ,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export default class SfProvarAuthStatus extends SfCommand<void> {
3
+ static readonly summary: string;
4
+ static readonly description: string;
5
+ static readonly examples: string[];
6
+ run(): Promise<void>;
7
+ }
@@ -0,0 +1,107 @@
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 { SfCommand } from '@salesforce/sf-plugins-core';
9
+ import { Messages } from '@provartesting/provardx-plugins-utils';
10
+ import { readStoredCredentials } from '../../../services/auth/credentials.js';
11
+ import { qualityHubClient, getQualityHubBaseUrl, REQUEST_ACCESS_URL } from '../../../services/qualityHub/client.js';
12
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
13
+ const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.status');
14
+ export default class SfProvarAuthStatus extends SfCommand {
15
+ static summary = messages.getMessage('summary');
16
+ static description = messages.getMessage('description');
17
+ static examples = messages.getMessages('examples');
18
+ async run() {
19
+ const envKey = process.env.PROVAR_API_KEY?.trim();
20
+ if (envKey) {
21
+ if (!envKey.startsWith('pv_k_')) {
22
+ this.log('Warning: PROVAR_API_KEY is set but invalid (does not start with "pv_k_").');
23
+ this.log(` Value: "${envKey.substring(0, 10)}..." — ignored for API calls.`);
24
+ this.log(' Fix: update PROVAR_API_KEY to a valid pv_k_ key from https://success.provartesting.com');
25
+ this.log('');
26
+ // Fall through to check stored credentials (matches resolveApiKey behaviour)
27
+ }
28
+ else {
29
+ this.log('API key configured');
30
+ this.log(' Source: environment variable (PROVAR_API_KEY)');
31
+ this.log(` Prefix: ${envKey.substring(0, 12)}`);
32
+ this.log('');
33
+ this.log(' Validation mode: Quality Hub API');
34
+ return;
35
+ }
36
+ }
37
+ const stored = readStoredCredentials();
38
+ if (stored) {
39
+ // Best-effort live check — silent fallback to cached values if offline or unconfigured.
40
+ // Does not run for env var keys (CI environments may not have outbound access).
41
+ let liveValid;
42
+ try {
43
+ const live = await qualityHubClient.fetchKeyStatus(stored.api_key, getQualityHubBaseUrl());
44
+ liveValid = live.valid;
45
+ if (live.username)
46
+ stored.username = live.username;
47
+ if (live.tier)
48
+ stored.tier = live.tier;
49
+ if (live.expires_at)
50
+ stored.expires_at = live.expires_at;
51
+ }
52
+ catch {
53
+ // Offline or API not yet configured — use locally cached values
54
+ }
55
+ if (liveValid === false) {
56
+ this.log('API key expired or revoked.');
57
+ this.log(' Source: ~/.provar/credentials.json');
58
+ this.log(` Prefix: ${stored.prefix}`);
59
+ this.log('');
60
+ this.log(' Run: sf provar auth login to refresh your key.');
61
+ return;
62
+ }
63
+ this.log('API key configured');
64
+ this.log(' Source: ~/.provar/credentials.json');
65
+ this.log(` Prefix: ${stored.prefix}`);
66
+ this.log(` Set at: ${stored.set_at}`);
67
+ if (stored.username)
68
+ this.log(` Account: ${stored.username}`);
69
+ if (stored.tier)
70
+ this.log(` Tier: ${stored.tier}`);
71
+ if (stored.expires_at) {
72
+ this.log(` Expires: ${stored.expires_at}`);
73
+ const expiresMs = new Date(stored.expires_at).getTime();
74
+ if (Number.isFinite(expiresMs)) {
75
+ const daysLeft = Math.ceil((expiresMs - Date.now()) / (1000 * 60 * 60 * 24));
76
+ if (daysLeft <= 14 && daysLeft > 0) {
77
+ this.log('');
78
+ this.log(` Warning: API key expires in ${daysLeft} day${daysLeft === 1 ? '' : 's'}.`);
79
+ this.log(" Run 'sf provar auth rotate' now to avoid CI/CD disruption.");
80
+ }
81
+ else if (daysLeft <= 0) {
82
+ this.log('');
83
+ this.log(' Warning: API key has expired. Run: sf provar auth login');
84
+ }
85
+ }
86
+ else {
87
+ this.log('');
88
+ this.log(' Warning: API key expiry timestamp is invalid.');
89
+ }
90
+ }
91
+ this.log('');
92
+ this.log(' Validation mode: Quality Hub API');
93
+ return;
94
+ }
95
+ this.log('No API key configured.');
96
+ this.log('');
97
+ this.log('To enable Quality Hub validation (170 rules):');
98
+ this.log(' Run: sf provar auth login');
99
+ this.log('');
100
+ this.log('For CI/CD: set the PROVAR_API_KEY environment variable.');
101
+ this.log('');
102
+ this.log(`No account? Request access at: ${REQUEST_ACCESS_URL}`);
103
+ this.log('');
104
+ this.log('Validation mode: local only (structural rules, no quality scoring)');
105
+ }
106
+ }
107
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/status.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAEpH,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,uBAAuB,CAAC,CAAC;AAE/F,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,SAAe;IACtD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;QAElD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;gBACtF,IAAI,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,+BAA+B,CAAC,CAAC;gBACjF,IAAI,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;gBACrG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACb,6EAA6E;YAC/E,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAC/B,IAAI,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;gBAC9D,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,wFAAwF;YACxF,gFAAgF;YAChF,IAAI,SAA8B,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAC;gBAC3F,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;gBACvB,IAAI,IAAI,CAAC,QAAQ;oBAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBACnD,IAAI,IAAI,CAAC,IAAI;oBAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBACvC,IAAI,IAAI,CAAC,UAAU;oBAAE,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;YAC3D,CAAC;YAAC,MAAM,CAAC;gBACP,gEAAgE;YAClE,CAAC;YAED,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;gBACxB,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;gBACxC,IAAI,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;gBACnD,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBACzC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACzC,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,QAAQ;gBAAE,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC7C,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;gBACxD,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;oBAC7E,IAAI,QAAQ,IAAI,EAAE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;wBACnC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACb,IAAI,CAAC,GAAG,CAAC,iCAAiC,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;wBACvF,IAAI,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;oBAC3E,CAAC;yBAAM,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;wBACzB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACb,IAAI,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;oBACxE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACb,IAAI,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QACpE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,kCAAkC,kBAAkB,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IACjF,CAAC"}