@provartesting/provardx-cli 1.4.7 → 1.5.0-dev.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 (122) hide show
  1. package/README.md +264 -9
  2. package/lib/commands/provar/automation/config/validate.js.map +1 -1
  3. package/lib/commands/provar/automation/project/validate.d.ts +14 -0
  4. package/lib/commands/provar/automation/project/validate.js +69 -0
  5. package/lib/commands/provar/automation/project/validate.js.map +1 -0
  6. package/lib/commands/provar/mcp/start.d.ts +16 -0
  7. package/lib/commands/provar/mcp/start.js +62 -0
  8. package/lib/commands/provar/mcp/start.js.map +1 -0
  9. package/lib/commands/provar/quality-hub/connect.d.ts +5 -0
  10. package/lib/commands/provar/quality-hub/connect.js +12 -0
  11. package/lib/commands/provar/quality-hub/connect.js.map +1 -0
  12. package/lib/commands/provar/quality-hub/display.d.ts +5 -0
  13. package/lib/commands/provar/quality-hub/display.js +12 -0
  14. package/lib/commands/provar/quality-hub/display.js.map +1 -0
  15. package/lib/commands/provar/quality-hub/open.d.ts +5 -0
  16. package/lib/commands/provar/quality-hub/open.js +12 -0
  17. package/lib/commands/provar/quality-hub/open.js.map +1 -0
  18. package/lib/commands/provar/quality-hub/test/run/abort.d.ts +5 -0
  19. package/lib/commands/provar/quality-hub/test/run/abort.js +12 -0
  20. package/lib/commands/provar/quality-hub/test/run/abort.js.map +1 -0
  21. package/lib/commands/provar/quality-hub/test/run/report.d.ts +5 -0
  22. package/lib/commands/provar/quality-hub/test/run/report.js +12 -0
  23. package/lib/commands/provar/quality-hub/test/run/report.js.map +1 -0
  24. package/lib/commands/provar/quality-hub/test/run.d.ts +5 -0
  25. package/lib/commands/provar/quality-hub/test/run.js +12 -0
  26. package/lib/commands/provar/quality-hub/test/run.js.map +1 -0
  27. package/lib/commands/provar/quality-hub/testcase/retrieve.d.ts +5 -0
  28. package/lib/commands/provar/quality-hub/testcase/retrieve.js +12 -0
  29. package/lib/commands/provar/quality-hub/testcase/retrieve.js.map +1 -0
  30. package/lib/mcp/licensing/algasClient.d.ts +19 -0
  31. package/lib/mcp/licensing/algasClient.js +144 -0
  32. package/lib/mcp/licensing/algasClient.js.map +1 -0
  33. package/lib/mcp/licensing/ideDetection.d.ts +34 -0
  34. package/lib/mcp/licensing/ideDetection.js +179 -0
  35. package/lib/mcp/licensing/ideDetection.js.map +1 -0
  36. package/lib/mcp/licensing/index.d.ts +5 -0
  37. package/lib/mcp/licensing/index.js +10 -0
  38. package/lib/mcp/licensing/index.js.map +1 -0
  39. package/lib/mcp/licensing/licenseCache.d.ts +20 -0
  40. package/lib/mcp/licensing/licenseCache.js +79 -0
  41. package/lib/mcp/licensing/licenseCache.js.map +1 -0
  42. package/lib/mcp/licensing/licenseError.d.ts +4 -0
  43. package/lib/mcp/licensing/licenseError.js +15 -0
  44. package/lib/mcp/licensing/licenseError.js.map +1 -0
  45. package/lib/mcp/licensing/licenseValidator.d.ts +33 -0
  46. package/lib/mcp/licensing/licenseValidator.js +103 -0
  47. package/lib/mcp/licensing/licenseValidator.js.map +1 -0
  48. package/lib/mcp/logging/logger.d.ts +7 -0
  49. package/lib/mcp/logging/logger.js +22 -0
  50. package/lib/mcp/logging/logger.js.map +1 -0
  51. package/lib/mcp/rules/page_object_validation_rules.json +344 -0
  52. package/lib/mcp/rules/provar_best_practices_rules.json +3192 -0
  53. package/lib/mcp/schemas/common.d.ts +20 -0
  54. package/lib/mcp/schemas/common.js +16 -0
  55. package/lib/mcp/schemas/common.js.map +1 -0
  56. package/lib/mcp/security/pathPolicy.d.ts +14 -0
  57. package/lib/mcp/security/pathPolicy.js +38 -0
  58. package/lib/mcp/security/pathPolicy.js.map +1 -0
  59. package/lib/mcp/server.d.ts +5 -0
  60. package/lib/mcp/server.js +59 -0
  61. package/lib/mcp/server.js.map +1 -0
  62. package/lib/mcp/tools/antTools.d.ts +21 -0
  63. package/lib/mcp/tools/antTools.js +602 -0
  64. package/lib/mcp/tools/antTools.js.map +1 -0
  65. package/lib/mcp/tools/automationTools.d.ts +14 -0
  66. package/lib/mcp/tools/automationTools.js +386 -0
  67. package/lib/mcp/tools/automationTools.js.map +1 -0
  68. package/lib/mcp/tools/bestPracticesEngine.d.ts +30 -0
  69. package/lib/mcp/tools/bestPracticesEngine.js +632 -0
  70. package/lib/mcp/tools/bestPracticesEngine.js.map +1 -0
  71. package/lib/mcp/tools/defectTools.d.ts +15 -0
  72. package/lib/mcp/tools/defectTools.js +199 -0
  73. package/lib/mcp/tools/defectTools.js.map +1 -0
  74. package/lib/mcp/tools/hierarchyValidate.d.ts +139 -0
  75. package/lib/mcp/tools/hierarchyValidate.js +540 -0
  76. package/lib/mcp/tools/hierarchyValidate.js.map +1 -0
  77. package/lib/mcp/tools/pageObjectGenerate.d.ts +3 -0
  78. package/lib/mcp/tools/pageObjectGenerate.js +153 -0
  79. package/lib/mcp/tools/pageObjectGenerate.js.map +1 -0
  80. package/lib/mcp/tools/pageObjectValidate.d.ts +18 -0
  81. package/lib/mcp/tools/pageObjectValidate.js +420 -0
  82. package/lib/mcp/tools/pageObjectValidate.js.map +1 -0
  83. package/lib/mcp/tools/projectInspect.d.ts +3 -0
  84. package/lib/mcp/tools/projectInspect.js +694 -0
  85. package/lib/mcp/tools/projectInspect.js.map +1 -0
  86. package/lib/mcp/tools/projectValidateFromPath.d.ts +3 -0
  87. package/lib/mcp/tools/projectValidateFromPath.js +153 -0
  88. package/lib/mcp/tools/projectValidateFromPath.js.map +1 -0
  89. package/lib/mcp/tools/propertiesTools.d.ts +7 -0
  90. package/lib/mcp/tools/propertiesTools.js +314 -0
  91. package/lib/mcp/tools/propertiesTools.js.map +1 -0
  92. package/lib/mcp/tools/qualityHubTools.d.ts +8 -0
  93. package/lib/mcp/tools/qualityHubTools.js +178 -0
  94. package/lib/mcp/tools/qualityHubTools.js.map +1 -0
  95. package/lib/mcp/tools/rcaTools.d.ts +4 -0
  96. package/lib/mcp/tools/rcaTools.js +620 -0
  97. package/lib/mcp/tools/rcaTools.js.map +1 -0
  98. package/lib/mcp/tools/sfSpawn.d.ts +28 -0
  99. package/lib/mcp/tools/sfSpawn.js +50 -0
  100. package/lib/mcp/tools/sfSpawn.js.map +1 -0
  101. package/lib/mcp/tools/testCaseGenerate.d.ts +3 -0
  102. package/lib/mcp/tools/testCaseGenerate.js +221 -0
  103. package/lib/mcp/tools/testCaseGenerate.js.map +1 -0
  104. package/lib/mcp/tools/testCaseValidate.d.ts +20 -0
  105. package/lib/mcp/tools/testCaseValidate.js +227 -0
  106. package/lib/mcp/tools/testCaseValidate.js.map +1 -0
  107. package/lib/mcp/tools/testPlanTools.d.ts +6 -0
  108. package/lib/mcp/tools/testPlanTools.js +311 -0
  109. package/lib/mcp/tools/testPlanTools.js.map +1 -0
  110. package/lib/mcp/tools/testPlanValidate.d.ts +2 -0
  111. package/lib/mcp/tools/testPlanValidate.js +75 -0
  112. package/lib/mcp/tools/testPlanValidate.js.map +1 -0
  113. package/lib/mcp/tools/testSuiteValidate.d.ts +2 -0
  114. package/lib/mcp/tools/testSuiteValidate.js +63 -0
  115. package/lib/mcp/tools/testSuiteValidate.js.map +1 -0
  116. package/lib/services/projectValidation.d.ts +119 -0
  117. package/lib/services/projectValidation.js +678 -0
  118. package/lib/services/projectValidation.js.map +1 -0
  119. package/messages/sf.provar.automation.project.validate.md +52 -0
  120. package/messages/sf.provar.mcp.start.md +74 -0
  121. package/oclif.manifest.json +1298 -1
  122. package/package.json +46 -23
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../../src/commands/provar/quality-hub/test/run.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,cAAc,MAAM,iFAAiF,CAAC;AAE7G,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,cAAc;IAC5D,MAAM,CAAU,OAAO,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACtD,MAAM,CAAU,gBAAgB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import ManagerTestcaseRetrieve from '@provartesting/provardx-plugins-manager/lib/commands/provar/manager/testcase/retrieve.js';
2
+ export default class SfProvarQualityHubTestcaseRetrieve extends ManagerTestcaseRetrieve {
3
+ static readonly aliases: string[];
4
+ static readonly deprecateAliases = true;
5
+ }
@@ -0,0 +1,12 @@
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 ManagerTestcaseRetrieve from '@provartesting/provardx-plugins-manager/lib/commands/provar/manager/testcase/retrieve.js';
8
+ export default class SfProvarQualityHubTestcaseRetrieve extends ManagerTestcaseRetrieve {
9
+ static aliases = ['provar:manager:testcase:retrieve'];
10
+ static deprecateAliases = true;
11
+ }
12
+ //# sourceMappingURL=retrieve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve.js","sourceRoot":"","sources":["../../../../../src/commands/provar/quality-hub/testcase/retrieve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,uBAAuB,MAAM,0FAA0F,CAAC;AAE/H,MAAM,CAAC,OAAO,OAAO,kCAAmC,SAAQ,uBAAuB;IAC9E,MAAM,CAAU,OAAO,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAC/D,MAAM,CAAU,gBAAgB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { LicenseType } from './licenseCache.js';
2
+ export interface AlgasResult {
3
+ valid: boolean;
4
+ licenseType: LicenseType;
5
+ expiresAt?: number;
6
+ }
7
+ /**
8
+ * Validate a license key against the Provar tag API.
9
+ *
10
+ * Returns { valid: true, licenseType: 'None' } when the key exists and is not deleted.
11
+ * The licenseType is 'None' because the tag endpoint does not expose the license type;
12
+ * licenseValidator.ts enriches the type via the IDE cross-reference step when possible.
13
+ */
14
+ export declare function validateKeyWithAlgas(licenseKey: string): Promise<AlgasResult>;
15
+ /**
16
+ * Exposed for testing only — resets the in-memory token cache.
17
+ * Do not call in production code.
18
+ */
19
+ export declare function resetTokenCacheForTest(): void;
@@ -0,0 +1,144 @@
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
+ /**
8
+ * algasClient.ts — Provar licensing API client.
9
+ *
10
+ * Validates a license key via the Provar tag API:
11
+ * 1. Obtain a short-lived Cognito Bearer token (client credentials flow, cached 50 min).
12
+ * 2. GET /studio/licensing/{licenseKey} — returns tag metadata including `deleted` flag.
13
+ *
14
+ * Validation semantics:
15
+ * - `deleted === false` → key exists in the Provar system and has not been revoked → valid.
16
+ * - `deleted === true` → key has been revoked → invalid.
17
+ * - HTTP 404 → key does not exist in the Provar system → invalid.
18
+ *
19
+ * Note: `validityPeriod` in the tag response is measured from the key's generation /
20
+ * modification date, NOT from now. It cannot be used to determine remaining validity.
21
+ * We rely on the tag's `deleted` flag only.
22
+ *
23
+ * The licenseType returned is 'None' when only the tag API is consulted (the tag endpoint
24
+ * does not expose the type). The IDE cross-reference step in licenseValidator.ts can
25
+ * supply a richer type when the key matches a locally-activated IDE license.
26
+ */
27
+ import { LicenseError } from './licenseError.js';
28
+ const TOKEN_URL = 'https://prod.provar.cloud/studio/licensingauth/oauth2/token';
29
+ const TAG_BASE_URL = 'https://prod.provar.cloud/studio/licensing';
30
+ /** Cognito tokens expire at 1h; cache for 50 min to allow a margin for clock skew. */
31
+ const TOKEN_TTL_MS = 50 * 60 * 1000;
32
+ const TIMEOUT_MS = 15000;
33
+ function getOAuthCredentials() {
34
+ const clientId = process.env['PROVAR_OAUTH_CLIENT_ID'];
35
+ const clientSecret = process.env['PROVAR_OAUTH_CLIENT_SECRET'];
36
+ if (!clientId || !clientSecret) {
37
+ throw new LicenseError('ALGAS_UNREACHABLE', 'Provar OAuth credentials are not configured.\n' +
38
+ 'Set PROVAR_OAUTH_CLIENT_ID and PROVAR_OAUTH_CLIENT_SECRET (see .env.example).');
39
+ }
40
+ return { clientId, clientSecret };
41
+ }
42
+ let cachedToken = null;
43
+ let tokenExpiresAt = 0;
44
+ async function getCognitoToken() {
45
+ if (cachedToken && Date.now() < tokenExpiresAt)
46
+ return cachedToken;
47
+ const { clientId, clientSecret } = getOAuthCredentials();
48
+ const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
49
+ const controller = new AbortController();
50
+ const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
51
+ try {
52
+ const res = await fetch(TOKEN_URL, {
53
+ method: 'POST',
54
+ headers: {
55
+ Authorization: `Basic ${credentials}`,
56
+ 'Content-Type': 'application/x-www-form-urlencoded',
57
+ },
58
+ body: 'grant_type=client_credentials&scope=studio-licensing-api%2Fread',
59
+ signal: controller.signal,
60
+ });
61
+ if (!res.ok) {
62
+ throw new LicenseError('ALGAS_HTTP_ERROR', `Provar licensing auth returned HTTP ${res.status}: ${res.statusText}`);
63
+ }
64
+ const json = (await res.json());
65
+ const token = String(json['access_token'] ?? '');
66
+ if (!token) {
67
+ throw new LicenseError('ALGAS_HTTP_ERROR', 'Empty access_token in Cognito response');
68
+ }
69
+ cachedToken = token;
70
+ tokenExpiresAt = Date.now() + TOKEN_TTL_MS;
71
+ return token;
72
+ }
73
+ catch (err) {
74
+ if (err.name === 'AbortError') {
75
+ throw new LicenseError('ALGAS_TIMEOUT', 'Provar licensing auth did not respond within 15s');
76
+ }
77
+ if (err instanceof LicenseError)
78
+ throw err;
79
+ throw new LicenseError('ALGAS_UNREACHABLE', `Could not reach Provar licensing auth: ${err.message}`);
80
+ }
81
+ finally {
82
+ clearTimeout(timeout);
83
+ }
84
+ }
85
+ /**
86
+ * Validate a license key against the Provar tag API.
87
+ *
88
+ * Returns { valid: true, licenseType: 'None' } when the key exists and is not deleted.
89
+ * The licenseType is 'None' because the tag endpoint does not expose the license type;
90
+ * licenseValidator.ts enriches the type via the IDE cross-reference step when possible.
91
+ */
92
+ export async function validateKeyWithAlgas(licenseKey) {
93
+ const controller = new AbortController();
94
+ const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
95
+ try {
96
+ const token = await getCognitoToken();
97
+ let res = await fetch(`${TAG_BASE_URL}/${encodeURIComponent(licenseKey)}`, {
98
+ headers: { Authorization: `Bearer ${token}` },
99
+ signal: controller.signal,
100
+ });
101
+ // 401 means the Cognito token was rotated mid-session — clear the module-level cache
102
+ // and retry exactly once with a fresh token before surfacing an error.
103
+ if (res.status === 401) {
104
+ cachedToken = null;
105
+ tokenExpiresAt = 0;
106
+ const refreshedToken = await getCognitoToken();
107
+ res = await fetch(`${TAG_BASE_URL}/${encodeURIComponent(licenseKey)}`, {
108
+ headers: { Authorization: `Bearer ${refreshedToken}` },
109
+ signal: controller.signal,
110
+ });
111
+ }
112
+ if (res.status === 404) {
113
+ // Key not found in the Provar system — definitively invalid
114
+ return { valid: false, licenseType: 'None' };
115
+ }
116
+ if (!res.ok) {
117
+ throw new LicenseError('ALGAS_HTTP_ERROR', `Provar licensing tag API returned HTTP ${res.status}: ${res.statusText}`);
118
+ }
119
+ const body = (await res.json());
120
+ const deleted = body['deleted'] === true;
121
+ // !deleted = key is present in the system and not revoked
122
+ return { valid: !deleted, licenseType: 'None' };
123
+ }
124
+ catch (err) {
125
+ if (err.name === 'AbortError') {
126
+ throw new LicenseError('ALGAS_TIMEOUT', 'Provar licensing tag API did not respond within 15s');
127
+ }
128
+ if (err instanceof LicenseError)
129
+ throw err;
130
+ throw new LicenseError('ALGAS_UNREACHABLE', `Could not reach Provar licensing API: ${err.message}`);
131
+ }
132
+ finally {
133
+ clearTimeout(timeout);
134
+ }
135
+ }
136
+ /**
137
+ * Exposed for testing only — resets the in-memory token cache.
138
+ * Do not call in production code.
139
+ */
140
+ export function resetTokenCacheForTest() {
141
+ cachedToken = null;
142
+ tokenExpiresAt = 0;
143
+ }
144
+ //# sourceMappingURL=algasClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algasClient.js","sourceRoot":"","sources":["../../../src/mcp/licensing/algasClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { LicenseType } from './licenseCache.js';
2
+ export interface IdeLicenseState {
3
+ /** Name of the .properties file (without extension). */
4
+ name: string;
5
+ licenseType: LicenseType;
6
+ activated: boolean;
7
+ /** When the IDE last checked this license online against ALGAS (Unix ms). */
8
+ lastOnlineCheckMs: number;
9
+ }
10
+ /**
11
+ * Read all .properties files from the Provar IDE license folder and return
12
+ * the activation state of each. Returns an empty array when the folder does
13
+ * not exist or cannot be read.
14
+ */
15
+ export declare function readIdeLicenses(): IdeLicenseState[];
16
+ /**
17
+ * Find the best activated IDE license, if any.
18
+ *
19
+ * Priority: most recently validated activated license.
20
+ * Returns null when no activated license is present.
21
+ */
22
+ export declare function findActivatedIdeLicense(): IdeLicenseState | null;
23
+ /**
24
+ * Search all IDE .properties files for one whose decrypted licenseKey matches
25
+ * the supplied raw key string.
26
+ *
27
+ * Used to cross-reference an explicit --license-key against the IDE's already-
28
+ * validated activation state without making a fresh API call.
29
+ *
30
+ * Returns the matching IdeLicenseState (which may have activated=false if the
31
+ * IDE recorded the key but it isn't currently activated), or null when no file
32
+ * decrypts to the given key.
33
+ */
34
+ export declare function findLicenseByDecryptedKey(rawKey: string): IdeLicenseState | null;
@@ -0,0 +1,179 @@
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
+ /**
8
+ * ideDetection.ts — Read activated Provar IDE license from disk.
9
+ *
10
+ * The Provar IDE stores license state in ~/Provar/.licenses/{name}.properties
11
+ *
12
+ * Fields we care about:
13
+ * - licenseStatus — Activated | NotActivated | Expired | Invalid | QuotaReached
14
+ * - licenseType — Fixed Seat | Floating | Trial | None
15
+ * - lastOnlineAvailabilityCheckUtc — epoch ms of last ALGAS check by the IDE
16
+ * - licenseKey — AES-128-ECB encrypted with key "provarautomation", Base64-encoded
17
+ *
18
+ * The licenseKey field is AES-128-ECB encrypted (LicenseSupport.KEY = "provarautomation").
19
+ * We decrypt it to allow cross-referencing an explicitly supplied --license-key against
20
+ * the IDE's already-validated license state without re-calling the licensing API.
21
+ */
22
+ import fs from 'node:fs';
23
+ import path from 'node:path';
24
+ import os from 'node:os';
25
+ import { createDecipheriv } from 'node:crypto';
26
+ /** AES-128-ECB key used by Provar IDE to encrypt the licenseKey field. */
27
+ const AES_KEY = Buffer.from('provarautomation'); // 16 bytes ASCII
28
+ /**
29
+ * Decrypt an AES-128-ECB + PKCS5 encrypted, Base64-encoded licenseKey field.
30
+ * Returns the plaintext string, or null if decryption fails (wrong key / corrupt).
31
+ */
32
+ function decryptLicenseKeyField(encryptedBase64) {
33
+ try {
34
+ const decipher = createDecipheriv('aes-128-ecb', AES_KEY, null);
35
+ const buf = Buffer.from(encryptedBase64, 'base64');
36
+ return Buffer.concat([decipher.update(buf), decipher.final()]).toString('utf-8');
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /** Mirrors License4J's DEFAUT_LICENSE_FOLDER_PATH + PROVAR_USER_HOME. */
43
+ function provarLicensesDir() {
44
+ const provarHome = process.env['PROVAR_HOME'] ?? path.join(os.homedir(), 'Provar');
45
+ return path.join(provarHome, '.licenses');
46
+ }
47
+ /**
48
+ * Parse a Java .properties file into a key→value map.
49
+ * Only handles simple `key=value` lines; ignores comments and blank lines.
50
+ */
51
+ function parseProperties(content) {
52
+ const map = new Map();
53
+ for (const line of content.split('\n')) {
54
+ const trimmed = line.trim();
55
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('!'))
56
+ continue;
57
+ const eqIdx = trimmed.indexOf('=');
58
+ if (eqIdx < 0)
59
+ continue;
60
+ const k = trimmed.slice(0, eqIdx).trim();
61
+ const v = trimmed.slice(eqIdx + 1).trim();
62
+ map.set(k, v);
63
+ }
64
+ return map;
65
+ }
66
+ function parseLicenseType(raw) {
67
+ // Java stores LicenseType.name() = "FixedSeat"; "Fixed Seat" kept for defensive compat.
68
+ if (raw === 'FixedSeat' || raw === 'Fixed Seat')
69
+ return 'FixedSeat';
70
+ if (raw === 'Floating')
71
+ return 'Floating';
72
+ if (raw === 'Trial')
73
+ return 'Trial';
74
+ return 'None';
75
+ }
76
+ /**
77
+ * Read all .properties files from the Provar IDE license folder and return
78
+ * the activation state of each. Returns an empty array when the folder does
79
+ * not exist or cannot be read.
80
+ */
81
+ export function readIdeLicenses() {
82
+ const dir = provarLicensesDir();
83
+ if (!fs.existsSync(dir))
84
+ return [];
85
+ const results = [];
86
+ let entries;
87
+ try {
88
+ entries = fs.readdirSync(dir, { withFileTypes: true });
89
+ }
90
+ catch {
91
+ return [];
92
+ }
93
+ for (const entry of entries) {
94
+ if (!entry.isFile() || !entry.name.endsWith('.properties'))
95
+ continue;
96
+ try {
97
+ const content = fs.readFileSync(path.join(dir, entry.name), 'utf-8');
98
+ const props = parseProperties(content);
99
+ const licenseStatus = props.get('licenseStatus') ?? '';
100
+ const licenseType = parseLicenseType(props.get('licenseType') ?? '');
101
+ const lastCheck = parseInt(props.get('lastOnlineAvailabilityCheckUtc') ?? '0', 10);
102
+ results.push({
103
+ name: entry.name.slice(0, -'.properties'.length),
104
+ licenseType,
105
+ activated: licenseStatus === 'Activated',
106
+ lastOnlineCheckMs: isNaN(lastCheck) ? 0 : lastCheck,
107
+ });
108
+ }
109
+ catch {
110
+ // Unreadable file — skip
111
+ }
112
+ }
113
+ return results;
114
+ }
115
+ /**
116
+ * Find the best activated IDE license, if any.
117
+ *
118
+ * Priority: most recently validated activated license.
119
+ * Returns null when no activated license is present.
120
+ */
121
+ export function findActivatedIdeLicense() {
122
+ const all = readIdeLicenses();
123
+ const activated = all.filter((l) => l.activated);
124
+ if (activated.length === 0)
125
+ return null;
126
+ // Return the one with the most recent online check
127
+ return activated.sort((a, b) => b.lastOnlineCheckMs - a.lastOnlineCheckMs)[0];
128
+ }
129
+ /**
130
+ * Search all IDE .properties files for one whose decrypted licenseKey matches
131
+ * the supplied raw key string.
132
+ *
133
+ * Used to cross-reference an explicit --license-key against the IDE's already-
134
+ * validated activation state without making a fresh API call.
135
+ *
136
+ * Returns the matching IdeLicenseState (which may have activated=false if the
137
+ * IDE recorded the key but it isn't currently activated), or null when no file
138
+ * decrypts to the given key.
139
+ */
140
+ export function findLicenseByDecryptedKey(rawKey) {
141
+ const dir = provarLicensesDir();
142
+ if (!fs.existsSync(dir))
143
+ return null;
144
+ let entries;
145
+ try {
146
+ entries = fs.readdirSync(dir, { withFileTypes: true });
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ for (const entry of entries) {
152
+ if (!entry.isFile() || !entry.name.endsWith('.properties'))
153
+ continue;
154
+ try {
155
+ const content = fs.readFileSync(path.join(dir, entry.name), 'utf-8');
156
+ const props = parseProperties(content);
157
+ const encryptedKey = props.get('licenseKey');
158
+ if (!encryptedKey)
159
+ continue;
160
+ const decrypted = decryptLicenseKeyField(encryptedKey);
161
+ if (decrypted !== rawKey)
162
+ continue;
163
+ const licenseStatus = props.get('licenseStatus') ?? '';
164
+ const licenseType = parseLicenseType(props.get('licenseType') ?? '');
165
+ const lastCheck = parseInt(props.get('lastOnlineAvailabilityCheckUtc') ?? '0', 10);
166
+ return {
167
+ name: entry.name.slice(0, -'.properties'.length),
168
+ licenseType,
169
+ activated: licenseStatus === 'Activated',
170
+ lastOnlineCheckMs: isNaN(lastCheck) ? 0 : lastCheck,
171
+ };
172
+ }
173
+ catch {
174
+ // Unreadable or corrupt file — skip
175
+ }
176
+ }
177
+ return null;
178
+ }
179
+ //# sourceMappingURL=ideDetection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ideDetection.js","sourceRoot":"","sources":["../../../src/mcp/licensing/ideDetection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { LicenseError } from './licenseError.js';
2
+ export { validateLicense } from './licenseValidator.js';
3
+ export type { LicenseValidationResult } from './licenseValidator.js';
4
+ export { findActivatedIdeLicense, readIdeLicenses } from './ideDetection.js';
5
+ export type { IdeLicenseState } from './ideDetection.js';
@@ -0,0 +1,10 @@
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
+ export { LicenseError } from './licenseError.js';
8
+ export { validateLicense } from './licenseValidator.js';
9
+ export { findActivatedIdeLicense, readIdeLicenses } from './ideDetection.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/licensing/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type LicenseType = 'Trial' | 'Floating' | 'FixedSeat' | 'None' | 'Whitelisted';
2
+ export interface CacheEntry {
3
+ keyHash: string;
4
+ valid: boolean;
5
+ licenseType: LicenseType;
6
+ checkedAt: number;
7
+ expiresAt?: number;
8
+ }
9
+ /** Re-validate against ALGAS after 2 hours — mirrors License4J's online check interval. */
10
+ export declare const ONLINE_TTL_MS: number;
11
+ /** Allow cached result for up to 48 hours when ALGAS is unreachable. */
12
+ export declare const OFFLINE_GRACE_MS: number;
13
+ /** Hash the raw license key so we never store it on disk. */
14
+ export declare function hashKey(licenseKey: string): string;
15
+ export declare function readCacheEntry(keyHash: string): CacheEntry | null;
16
+ export declare function writeCacheEntry(entry: CacheEntry): void;
17
+ /** True when the cached entry is fresh enough to skip the next ALGAS call. */
18
+ export declare function isCacheEntryFresh(entry: CacheEntry): boolean;
19
+ /** True when the cached entry is within the 48-hour offline grace window. */
20
+ export declare function isCacheEntryWithinGrace(entry: CacheEntry): boolean;
@@ -0,0 +1,79 @@
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 fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import os from 'node:os';
10
+ import { createHash } from 'node:crypto';
11
+ /**
12
+ * Store the MCP license cache alongside the Provar IDE's own license folder
13
+ * (~/Provar/.licenses/) so there is a single authoritative location for all
14
+ * Provar license state on the machine. This also enables auto-detection when
15
+ * a user switches from Provar Automation IDE to Claude + MCP.
16
+ *
17
+ * Computed lazily so tests can redirect HOME/USERPROFILE before calling any
18
+ * cache function without the path being baked in at module-load time.
19
+ */
20
+ function cacheDir() {
21
+ const provarHome = process.env['PROVAR_HOME'] ?? path.join(os.homedir(), 'Provar');
22
+ return path.join(provarHome, '.licenses');
23
+ }
24
+ function cacheFile() {
25
+ return path.join(cacheDir(), '.mcp-license-cache.json');
26
+ }
27
+ /** Re-validate against ALGAS after 2 hours — mirrors License4J's online check interval. */
28
+ export const ONLINE_TTL_MS = 2 * 60 * 60 * 1000;
29
+ /** Allow cached result for up to 48 hours when ALGAS is unreachable. */
30
+ export const OFFLINE_GRACE_MS = 48 * 60 * 60 * 1000;
31
+ /** Hash the raw license key so we never store it on disk. */
32
+ export function hashKey(licenseKey) {
33
+ return createHash('sha256').update(licenseKey).digest('hex');
34
+ }
35
+ export function readCacheEntry(keyHash) {
36
+ try {
37
+ const file = cacheFile();
38
+ if (!fs.existsSync(file))
39
+ return null;
40
+ const raw = fs.readFileSync(file, 'utf-8');
41
+ const cache = JSON.parse(raw);
42
+ return cache[keyHash] ?? null;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ export function writeCacheEntry(entry) {
49
+ try {
50
+ const dir = cacheDir();
51
+ const file = cacheFile();
52
+ if (!fs.existsSync(dir)) {
53
+ fs.mkdirSync(dir, { recursive: true });
54
+ }
55
+ let cache = {};
56
+ if (fs.existsSync(file)) {
57
+ try {
58
+ cache = JSON.parse(fs.readFileSync(file, 'utf-8'));
59
+ }
60
+ catch {
61
+ cache = {};
62
+ }
63
+ }
64
+ cache[entry.keyHash] = entry;
65
+ fs.writeFileSync(file, JSON.stringify(cache, null, 2), 'utf-8');
66
+ }
67
+ catch {
68
+ // Cache write failure is non-fatal; validation result still returned to caller.
69
+ }
70
+ }
71
+ /** True when the cached entry is fresh enough to skip the next ALGAS call. */
72
+ export function isCacheEntryFresh(entry) {
73
+ return Date.now() - entry.checkedAt < ONLINE_TTL_MS;
74
+ }
75
+ /** True when the cached entry is within the 48-hour offline grace window. */
76
+ export function isCacheEntryWithinGrace(entry) {
77
+ return Date.now() - entry.checkedAt < OFFLINE_GRACE_MS;
78
+ }
79
+ //# sourceMappingURL=licenseCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licenseCache.js","sourceRoot":"","sources":["../../../src/mcp/licensing/licenseCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare class LicenseError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string);
4
+ }
@@ -0,0 +1,15 @@
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
+ export class LicenseError extends Error {
8
+ code;
9
+ constructor(code, message) {
10
+ super(message);
11
+ this.name = 'LicenseError';
12
+ this.code = code;
13
+ }
14
+ }
15
+ //# sourceMappingURL=licenseError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licenseError.js","sourceRoot":"","sources":["../../../src/mcp/licensing/licenseError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrB,IAAI,CAAS;IAE7B,YAAmB,IAAY,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ import { type LicenseType } from './licenseCache.js';
2
+ export interface LicenseValidationResult {
3
+ valid: boolean;
4
+ licenseType: LicenseType;
5
+ /** True when the result came from disk cache rather than a live ALGAS call. */
6
+ fromCache: boolean;
7
+ /** True when ALGAS was unreachable and we fell back to the offline grace window. */
8
+ offlineGrace: boolean;
9
+ }
10
+ /**
11
+ * Validate the Provar license before starting the MCP server.
12
+ *
13
+ * Requires Provar Automation IDE to be installed with an activated licence.
14
+ * We trust the IDE's own licenseStatus field — if it says "Activated" we
15
+ * accept it. The IDE is responsible for setting licenseStatus to "Expired"
16
+ * or "Invalid" when a licence lapses; we do not re-check timing ourselves.
17
+ *
18
+ * The result is cached so repeated starts within 2 hours skip the IDE file
19
+ * read entirely. The 48-hour grace window lets the MCP server keep running
20
+ * when the IDE files become temporarily inaccessible (e.g. network share,
21
+ * permission change) after a successful read.
22
+ *
23
+ * Validation flow:
24
+ * 1. MCP cache fresh (< 2h) → serve from cache, skip IDE read
25
+ * 2. Scan ~/Provar/.licenses/*.properties for an Activated licence
26
+ * 3. Found → write cache, accept (offlineGrace=false)
27
+ * 4. Not found but MCP cache within 48h grace → serve, offlineGrace=true
28
+ * 5. Not found, no usable cache → throw LICENSE_NOT_FOUND
29
+ *
30
+ * When NODE_ENV=test this function returns immediately so unit tests never
31
+ * touch the filesystem.
32
+ */
33
+ export declare function validateLicense(): Promise<LicenseValidationResult>;