From 0471b1232fd34f5906e61a5fa08e32971f23fe0c Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Thu, 18 Dec 2025 19:54:25 -0500 Subject: [PATCH 1/4] feat: options, path resolves, nodejs version, annotations --- src/options.defaults.ts | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/options.defaults.ts b/src/options.defaults.ts index 9275388..b4750a4 100644 --- a/src/options.defaults.ts +++ b/src/options.defaults.ts @@ -1,13 +1,15 @@ -import { basename, join } from 'node:path'; +import { basename, join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; import packageJson from '../package.json'; /** - * Application defaults, not user-configurable + * Application defaults, not all fields are user-configurable * * @interface DefaultOptions * * @template TLogOptions The logging options type, defaulting to LoggingOptions. * @property contextPath - Current working directory. + * @property contextUrl - Current working directory URL. * @property docsHost - Flag indicating whether to use the docs-host. * @property docsPath - Path to the documentation directory. * @property isHttp - Flag indicating whether the server is running in HTTP mode. @@ -15,12 +17,13 @@ import packageJson from '../package.json'; * @property llmsFilesPath - Path to the LLMs files directory. * @property {LoggingOptions} logging - Logging options. * @property name - Name of the package. + * @property nodeVersion - Node.js major version. * @property repoName - Name of the repository. * @property pfExternal - PatternFly external docs URL. * @property pfExternalDesignComponents - PatternFly design guidelines' components' URL. * @property pfExternalExamplesComponents - PatternFly examples' core components' URL. * @property pfExternalExamplesLayouts - PatternFly examples' core layouts' URL. - * @property pfExternalExamplesCharts - PatternFly examples' charts' components' URL.' + * @property pfExternalExamplesCharts - PatternFly examples' charts' components' URL. * @property pfExternalExamplesTable - PatternFly examples' table components' URL. * @property pfExternalChartsDesign - PatternFly charts' design guidelines URL. * @property pfExternalDesignLayouts - PatternFly design guidelines' layouts' URL. @@ -33,6 +36,7 @@ import packageJson from '../package.json'; */ interface DefaultOptions { contextPath: string; + contextUrl: string; docsHost: boolean; docsPath: string; http: HttpOptions; @@ -40,6 +44,7 @@ interface DefaultOptions { llmsFilesPath: string; logging: TLogOptions; name: string; + nodeVersion: number; pfExternal: string; pfExternalDesignComponents: string; pfExternalExamplesComponents: string; @@ -253,6 +258,19 @@ const PF_EXTERNAL_ACCESSIBILITY = `${PF_EXTERNAL}/accessibility`; */ const PF_EXTERNAL_CHARTS_DESIGN = `${PF_EXTERNAL}/design-guidelines/charts`; +/** + * Get the current Node.js major version. + */ +const getNodeMajorVersion = () => { + const major = Number.parseInt(process.versions.node.split('.')[0] || '0', 10); + + if (Number.isFinite(major)) { + return major; + } + + return 0; +}; + /** * Global default options. Base defaults before CLI/programmatic overrides. * @@ -260,13 +278,15 @@ const PF_EXTERNAL_CHARTS_DESIGN = `${PF_EXTERNAL}/design-guidelines/charts`; */ const DEFAULT_OPTIONS: DefaultOptions = { docsHost: false, - contextPath: (process.env.NODE_ENV === 'local' && '/') || process.cwd(), - docsPath: (process.env.NODE_ENV === 'local' && '/documentation') || join(process.cwd(), 'documentation'), + contextPath: (process.env.NODE_ENV === 'local' && '/') || resolve(process.cwd()), + contextUrl: pathToFileURL((process.env.NODE_ENV === 'local' && '/') || resolve(process.cwd())).href, + docsPath: (process.env.NODE_ENV === 'local' && '/documentation') || join(resolve(process.cwd()), 'documentation'), isHttp: false, http: HTTP_OPTIONS, - llmsFilesPath: (process.env.NODE_ENV === 'local' && '/llms-files') || join(process.cwd(), 'llms-files'), + llmsFilesPath: (process.env.NODE_ENV === 'local' && '/llms-files') || join(resolve(process.cwd()), 'llms-files'), logging: LOGGING_OPTIONS, name: packageJson.name, + nodeVersion: (process.env.NODE_ENV === 'local' && 22) || getNodeMajorVersion(), pfExternal: PF_EXTERNAL, pfExternalDesignComponents: PF_EXTERNAL_DESIGN_COMPONENTS, pfExternalExamplesComponents: PF_EXTERNAL_EXAMPLES_REACT_CORE, @@ -299,6 +319,7 @@ export { PF_EXTERNAL_ACCESSIBILITY, LOG_BASENAME, DEFAULT_OPTIONS, + getNodeMajorVersion, type DefaultOptions, type DefaultOptionsOverrides, type HttpOptions, From 558612b27a0a32261f8553b90967b3dea9029b6a Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Fri, 19 Dec 2025 12:28:39 -0500 Subject: [PATCH 2/4] test: expected updates --- src/__tests__/__snapshots__/options.defaults.test.ts.snap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/__tests__/__snapshots__/options.defaults.test.ts.snap b/src/__tests__/__snapshots__/options.defaults.test.ts.snap index 302b31a..a247c5a 100644 --- a/src/__tests__/__snapshots__/options.defaults.test.ts.snap +++ b/src/__tests__/__snapshots__/options.defaults.test.ts.snap @@ -4,6 +4,7 @@ exports[`options defaults should return specific properties 1`] = ` { "DEFAULT_OPTIONS": { "contextPath": "/", + "contextUrl": "file:///", "docsHost": false, "docsPath": "/documentation", "http": { @@ -22,6 +23,7 @@ exports[`options defaults should return specific properties 1`] = ` "transport": "stdio", }, "name": "@patternfly/patternfly-mcp", + "nodeVersion": 22, "pfExternal": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content", "pfExternalAccessibility": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/accessibility", "pfExternalChartsDesign": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/charts", @@ -80,5 +82,6 @@ exports[`options defaults should return specific properties 1`] = ` "PF_EXTERNAL_EXAMPLES_TABLE": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-table/src/components", "PF_EXTERNAL_EXAMPLES_VERSION": "v6.4.0", "PF_EXTERNAL_VERSION": "fb05713aba75998b5ecf5299ee3c1a259119bd74", + "getNodeMajorVersion": [Function], } `; From e73b8cf6fcaf4fb67b4cf5a4933800dd39d81286 Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Fri, 19 Dec 2025 12:58:35 -0500 Subject: [PATCH 3/4] test: node major --- .../options.defaults.test.ts.snap | 130 ++++++++---------- src/__tests__/options.defaults.test.ts | 11 +- src/options.defaults.ts | 8 +- 3 files changed, 72 insertions(+), 77 deletions(-) diff --git a/src/__tests__/__snapshots__/options.defaults.test.ts.snap b/src/__tests__/__snapshots__/options.defaults.test.ts.snap index a247c5a..9219708 100644 --- a/src/__tests__/__snapshots__/options.defaults.test.ts.snap +++ b/src/__tests__/__snapshots__/options.defaults.test.ts.snap @@ -1,87 +1,71 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`options defaults should return specific properties 1`] = ` +exports[`options defaults should return specific properties: defaults 1`] = ` { - "DEFAULT_OPTIONS": { - "contextPath": "/", - "contextUrl": "file:///", - "docsHost": false, - "docsPath": "/documentation", - "http": { - "allowedHosts": [], - "allowedOrigins": [], - "host": "127.0.0.1", - "port": 8080, + "contextPath": "/", + "contextUrl": "file:///", + "docsHost": false, + "docsPath": "/documentation", + "http": { + "allowedHosts": [], + "allowedOrigins": [], + "host": "127.0.0.1", + "port": 8080, + }, + "isHttp": false, + "llmsFilesPath": "/llms-files", + "logging": { + "level": "info", + "logger": "@patternfly/patternfly-mcp", + "protocol": false, + "stderr": false, + "transport": "stdio", + }, + "name": "@patternfly/patternfly-mcp", + "nodeVersion": 22, + "pfExternal": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content", + "pfExternalAccessibility": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/accessibility", + "pfExternalChartsDesign": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/charts", + "pfExternalDesignComponents": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/components", + "pfExternalDesignLayouts": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/layouts", + "pfExternalExamplesCharts": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-charts/src/victory/components", + "pfExternalExamplesComponents": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/components", + "pfExternalExamplesLayouts": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/layouts", + "pfExternalExamplesTable": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-table/src/components", + "repoName": "patternfly-mcp", + "resourceMemoOptions": { + "default": { + "cacheLimit": 3, }, - "isHttp": false, - "llmsFilesPath": "/llms-files", - "logging": { - "level": "info", - "logger": "@patternfly/patternfly-mcp", - "protocol": false, - "stderr": false, - "transport": "stdio", + "fetchUrl": { + "cacheErrors": false, + "cacheLimit": 100, + "expire": 180000, }, - "name": "@patternfly/patternfly-mcp", - "nodeVersion": 22, - "pfExternal": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content", - "pfExternalAccessibility": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/accessibility", - "pfExternalChartsDesign": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/charts", - "pfExternalDesignComponents": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/components", - "pfExternalDesignLayouts": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/layouts", - "pfExternalExamplesCharts": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-charts/src/victory/components", - "pfExternalExamplesComponents": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/components", - "pfExternalExamplesLayouts": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/layouts", - "pfExternalExamplesTable": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-table/src/components", - "repoName": "patternfly-mcp", - "resourceMemoOptions": { - "default": { - "cacheLimit": 3, - }, - "fetchUrl": { - "cacheErrors": false, - "cacheLimit": 100, - "expire": 180000, - }, - "readFile": { - "cacheErrors": false, - "cacheLimit": 50, - "expire": 120000, - }, + "readFile": { + "cacheErrors": false, + "cacheLimit": 50, + "expire": 120000, }, - "separator": " + }, + "separator": " --- ", - "toolMemoOptions": { - "fetchDocs": { - "cacheErrors": false, - "cacheLimit": 15, - "expire": 60000, - }, - "usePatternFlyDocs": { - "cacheErrors": false, - "cacheLimit": 10, - "expire": 60000, - }, + "toolMemoOptions": { + "fetchDocs": { + "cacheErrors": false, + "cacheLimit": 15, + "expire": 60000, + }, + "usePatternFlyDocs": { + "cacheErrors": false, + "cacheLimit": 10, + "expire": 60000, }, - "urlRegex": /\\^\\(https\\?:\\)\\\\/\\\\//i, - "version": "0.0.0", }, - "LOG_BASENAME": "pf-mcp:log", - "PF_EXTERNAL": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content", - "PF_EXTERNAL_ACCESSIBILITY": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/accessibility", - "PF_EXTERNAL_CHARTS_DESIGN": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/charts", - "PF_EXTERNAL_DESIGN_COMPONENTS": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/components", - "PF_EXTERNAL_DESIGN_LAYOUTS": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content/design-guidelines/layouts", - "PF_EXTERNAL_EXAMPLES": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages", - "PF_EXTERNAL_EXAMPLES_CHARTS": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-charts/src/victory/components", - "PF_EXTERNAL_EXAMPLES_LAYOUTS": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/layouts", - "PF_EXTERNAL_EXAMPLES_REACT_CORE": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-core/src/components", - "PF_EXTERNAL_EXAMPLES_TABLE": "https://raw.githubusercontent.com/patternfly/patternfly-react/refs/tags/v6.4.0/packages/react-table/src/components", - "PF_EXTERNAL_EXAMPLES_VERSION": "v6.4.0", - "PF_EXTERNAL_VERSION": "fb05713aba75998b5ecf5299ee3c1a259119bd74", - "getNodeMajorVersion": [Function], + "urlRegex": /\\^\\(https\\?:\\)\\\\/\\\\//i, + "version": "0.0.0", } `; diff --git a/src/__tests__/options.defaults.test.ts b/src/__tests__/options.defaults.test.ts index a31464d..e8f1b68 100644 --- a/src/__tests__/options.defaults.test.ts +++ b/src/__tests__/options.defaults.test.ts @@ -1,7 +1,14 @@ -import * as options from '../options.defaults'; +import { DEFAULT_OPTIONS, getNodeMajorVersion } from '../options.defaults'; describe('options defaults', () => { it('should return specific properties', () => { - expect(options).toMatchSnapshot(); + expect(DEFAULT_OPTIONS).toMatchSnapshot('defaults'); + }); +}); + +describe('getNodeMajorVersion', () => { + it('should get the current Node.js version', () => { + // Purposeful failure in the event the process.versions.node value is not available + expect(getNodeMajorVersion()).not.toBe(0); }); }); diff --git a/src/options.defaults.ts b/src/options.defaults.ts index b4750a4..bda9a15 100644 --- a/src/options.defaults.ts +++ b/src/options.defaults.ts @@ -260,9 +260,13 @@ const PF_EXTERNAL_CHARTS_DESIGN = `${PF_EXTERNAL}/design-guidelines/charts`; /** * Get the current Node.js major version. + * + * @param nodeVersion + * @returns Node.js major version. */ -const getNodeMajorVersion = () => { - const major = Number.parseInt(process.versions.node.split('.')[0] || '0', 10); +const getNodeMajorVersion = (nodeVersion = process.versions.node) => { + const updatedNodeVersion = nodeVersion || '0.0.0'; + const major = Number.parseInt(updatedNodeVersion.split('.')[0] || '0', 10); if (Number.isFinite(major)) { return major; From 106eca122d1bbb9f4a8d398656512d06e1db424a Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Fri, 19 Dec 2025 13:08:50 -0500 Subject: [PATCH 4/4] test: optional chain --- src/__tests__/options.defaults.test.ts | 17 +++++++++++++++++ src/options.defaults.ts | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/__tests__/options.defaults.test.ts b/src/__tests__/options.defaults.test.ts index e8f1b68..3e5e254 100644 --- a/src/__tests__/options.defaults.test.ts +++ b/src/__tests__/options.defaults.test.ts @@ -11,4 +11,21 @@ describe('getNodeMajorVersion', () => { // Purposeful failure in the event the process.versions.node value is not available expect(getNodeMajorVersion()).not.toBe(0); }); + + it.each([ + { + description: 'number', + value: 1_000_000 + }, + { + description: 'string', + value: 'lorem ipsum' + }, + { + description: 'null', + value: null + } + ])('should handle basic failure, $description', ({ value }) => { + expect(getNodeMajorVersion(value as any)).toBe(0); + }); }); diff --git a/src/options.defaults.ts b/src/options.defaults.ts index bda9a15..e35aa7a 100644 --- a/src/options.defaults.ts +++ b/src/options.defaults.ts @@ -266,7 +266,7 @@ const PF_EXTERNAL_CHARTS_DESIGN = `${PF_EXTERNAL}/design-guidelines/charts`; */ const getNodeMajorVersion = (nodeVersion = process.versions.node) => { const updatedNodeVersion = nodeVersion || '0.0.0'; - const major = Number.parseInt(updatedNodeVersion.split('.')[0] || '0', 10); + const major = Number.parseInt(updatedNodeVersion?.split?.('.')?.[0] || '0', 10); if (Number.isFinite(major)) { return major;