diff --git a/.changeset/many-knives-attend.md b/.changeset/many-knives-attend.md new file mode 100644 index 00000000..8d98d648 --- /dev/null +++ b/.changeset/many-knives-attend.md @@ -0,0 +1,5 @@ +--- +'@salesforce/b2c-dx-docs': minor +--- + +Added MCP Server documentation diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 711dc041..6b14c455 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,7 +44,7 @@ Issues labelled `good first contribution`. # Running the MCP server from source -When developing the B2C DX MCP package (`packages/b2c-dx-mcp`), use `node` with the path to `bin/dev.js` in args. Build to latest (`pnpm run build` from the repo root) so changes that require a rebuild are reflected when you run the server. +For information on running the MCP server from source and local development, see [packages/b2c-dx-mcp/CONTRIBUTING.md](packages/b2c-dx-mcp/CONTRIBUTING.md). # Contribution Checklist diff --git a/README.md b/README.md index 35601dab..a308b650 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ > [!NOTE] > This project is currently in **Developer Preview**. Not all features are implemented, and the API may change in future releases. Please provide feedback via GitHub issues and Unofficial Slack. -Salesforce Commerce Cloud B2C Command Line Tools. +Salesforce B2C Commerce Command Line Tools. > [!TIP] > **Just looking for the B2C CLI or MCP install instructions?** Visit the documentation site at [https://salesforcecommercecloud.github.io/b2c-developer-tooling/](https://salesforcecommercecloud.github.io/b2c-developer-tooling/) for the latest install guide and CLI reference. diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index cf00835f..dd5ee68c 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -51,6 +51,15 @@ const guideSidebar = [ {text: 'Storefront Next', link: '/guide/storefront-next'}, ], }, + { + text: 'MCP Server', + items: [ + {text: 'Overview', link: '/mcp/'}, + {text: 'Installation', link: '/mcp/installation'}, + {text: 'Configuration', link: '/mcp/configuration'}, + {text: 'Toolsets & Tools', link: '/mcp/toolsets'}, + ], + }, { text: 'Extending', items: [ @@ -83,6 +92,16 @@ const guideSidebar = [ {text: 'Logging', link: '/cli/logging'}, ], }, + { + text: 'Tools Reference', + items: [ + {text: 'cartridge_deploy', link: '/mcp/tools/cartridge-deploy'}, + {text: 'mrt_bundle_push', link: '/mcp/tools/mrt-bundle-push'}, + {text: 'scapi_schemas_list', link: '/mcp/tools/scapi-schemas-list'}, + {text: 'scapi_custom_apis_status', link: '/mcp/tools/scapi-custom-apis-status'}, + {text: 'storefront_next_page_designer_decorator', link: '/mcp/tools/storefront-next-page-designer-decorator'}, + ], + }, ]; // Script to force hard navigation for version switching links @@ -111,7 +130,7 @@ document.addEventListener('click', (e) => { export default defineConfig({ title: 'B2C DX', - description: 'Salesforce Commerce Cloud B2C Developer Experience - CLI, MCP Server, and SDK', + description: 'Salesforce B2C Commerce Developer Experience - CLI, MCP Server, and SDK', base: basePath, head: [['script', {}, versionSwitchScript]], @@ -132,6 +151,7 @@ export default defineConfig({ nav: [ {text: 'Guide', link: '/guide/'}, {text: 'CLI Reference', link: '/cli/'}, + {text: 'MCP Server', link: '/mcp/'}, {text: 'API Reference', link: '/api/'}, { text: isDevBuild ? 'Dev' : 'Latest', @@ -147,6 +167,7 @@ export default defineConfig({ sidebar: { '/guide/': guideSidebar, '/cli/': guideSidebar, + '/mcp/': guideSidebar, '/api/': [ { text: 'API Reference', diff --git a/docs/guide/account-manager.md b/docs/guide/account-manager.md index 588e919c..cc1a316d 100644 --- a/docs/guide/account-manager.md +++ b/docs/guide/account-manager.md @@ -1,10 +1,10 @@ --- -description: Managing Account Manager users, roles, organizations, and API clients with the B2C CLI — including authentication options, CI/CD automation, and common workflows. +description: Manage Account Manager users, roles, organizations, and API clients with the B2C CLI, including authentication options, CI/CD automation, and common workflows. --- # Account Manager Guide -The B2C CLI provides commands for managing Account Manager resources — users, roles, organizations, and API clients — directly from the terminal. This guide covers authentication setup, common workflows, and CI/CD automation. +The B2C CLI provides commands for managing Account Manager resources—users, roles, organizations, and API clients—directly from the terminal. This guide covers authentication setup, common workflows, and CI/CD automation. ::: tip For the full command reference with all flags and options, see [Account Manager Commands](/cli/account-manager). @@ -12,11 +12,11 @@ For the full command reference with all flags and options, see [Account Manager ## Authentication -Account Manager commands work out of the box — no configuration required. The CLI uses a built-in public client that authenticates via browser login. For automation, you can provide your own API client credentials. +Account Manager commands work out of the box—no configuration is required. The CLI uses a built—in public client that authenticates via browser login. For automation, you can provide your own API client credentials. ### Zero-Config (Default) -Just run commands. The CLI opens a browser for login using the built-in client: +Just run the commands without configuring any settings. The CLI opens a browser for login using the built-in client. ```bash # Works immediately — opens browser for login @@ -40,7 +40,7 @@ b2c am orgs list --user-auth ### Client Credentials -Uses the API client's secret for non-interactive authentication. Best for CI/CD pipelines, scripts, and automation. +Uses the API client's secret for non-interactive authentication. This option is best for CI/CD pipelines, scripts, and automation. ```bash # List users with client credentials @@ -53,11 +53,11 @@ Requirements: ### Authentication Order -By default, the CLI tries client credentials first (if `--client-secret` is provided), then falls back to browser-based user authentication (using either your configured `--client-id` or the built-in public client). To force browser-based login, pass `--user-auth`. +By default, the CLI tries client credentials first (if `--client-secret` is provided), then falls back to browser-based user authentication by using either your configured `--client-id` or the built-in public client. To force browser-based login, pass `--user-auth`. ### Role Requirements -Different operations require different roles, and the required roles depend on how you authenticate: +Different operations require different roles, and the required roles depend on how you authenticate. | Operations | Client Credentials (roles on API client) | User Auth (roles on user account) | |---|---|---| @@ -75,18 +75,18 @@ If authentication fails, the CLI provides contextual error messages recommending ### For Interactive Use -No setup required. Account Manager commands use the CLI's built-in public client by default: +No setup required. Account Manager commands use the CLI's built-in public client by default. ```bash b2c am users list ``` -If you need to use your own API client (for specific scopes or organization restrictions): +If you need to use your own API client for specific scopes or organization restrictions: -1. In [Account Manager](https://account.demandware.com), find or create an API client -2. Under **Redirect URLs**, add `http://localhost:8080` -3. Under **Allowed Scopes**, add: `mail roles tenantFilter openid` -4. Set **Default Scopes** to: `mail roles tenantFilter openid` +1. In [Account Manager](https://account.demandware.com), find or create an API client. +2. Under **Redirect URLs**, add `http://localhost:8080`. +3. Under **Allowed Scopes**, add: `mail roles tenantFilter openid`. +4. Set **Default Scopes** to: `mail roles tenantFilter openid`. ```bash export SFCC_CLIENT_ID=your-client-id @@ -95,12 +95,12 @@ b2c am users list --user-auth ### For CI/CD and Automation -1. In [Account Manager](https://account.demandware.com), create a dedicated API client -2. Set a strong password (client secret) and save it securely -3. Set **Token Endpoint Auth Method** to `client_secret_post` -4. Under **Roles**, add **User Administrator** (for user/role management) -5. Under **Allowed Scopes**, add: `mail roles tenantFilter openid` -6. Set **Default Scopes** to: `mail roles tenantFilter openid` +1. In [Account Manager](https://account.demandware.com), create a dedicated API client. +2. Set a strong password (client secret) and save it securely. +3. Set **Token Endpoint Auth Method** to `client_secret_post`. +4. Under **Roles**, add **User Administrator** (for user/role management). +5. Under **Allowed Scopes**, add: `mail roles tenantFilter openid`. +6. Set **Default Scopes** to: `mail roles tenantFilter openid`. Then configure your CI/CD environment: @@ -110,7 +110,7 @@ export SFCC_CLIENT_SECRET=your-client-secret ``` ::: tip -Store the client secret in your CI/CD system's secrets manager — never commit it to source control. +Store the client secret in your CI/CD system's secrets manager—never commit it to source control. ::: ## Common Workflows @@ -236,7 +236,7 @@ The CLI will suggest the specific role or auth method needed. Common fixes: ### "No valid auth method available" -The CLI could not find credentials for any allowed auth method: +The CLI couldn't find credentials for any allowed auth method: - Verify `--client-id` is set (or `SFCC_CLIENT_ID` environment variable) - For client credentials, verify `--client-secret` is set diff --git a/docs/guide/agent-skills.md b/docs/guide/agent-skills.md index dfd8d717..f7867ccc 100644 --- a/docs/guide/agent-skills.md +++ b/docs/guide/agent-skills.md @@ -12,10 +12,10 @@ These skills follow the [Agent Skills](https://agentskills.io/home) standard and When installed, the skills teach AI assistants about B2C Commerce development, CLI commands, and best practices, enabling them to help you with: -- **CLI Operations** - Deploying cartridges, running jobs, managing sandboxes, WebDAV operations -- **B2C Development** - Controllers, ISML templates, forms, localization, logging, metadata -- **Web Services** - HTTP/SOAP/FTP integrations using the Service Framework -- **Custom APIs** - Building SCAPI Custom APIs with contracts, implementations, and mappings +- **CLI Operations**: Deploying cartridges, running jobs, managing sandboxes, WebDAV operations +- **B2C Development**: Controllers, ISML templates, forms, localization, logging, metadata +- **Web Services**: HTTP/SOAP/FTP integrations using the Service Framework +- **Custom APIs**: Building SCAPI Custom APIs with contracts, implementations, and mappings ## Available Plugins @@ -26,7 +26,7 @@ When installed, the skills teach AI assistants about B2C Commerce development, C ### Plugin: b2c-cli -Skills for using the B2C CLI to manage your Commerce Cloud instances. Covers code deployment, job execution, site archive import/export, WebDAV file operations, On-Demand Sandbox management, and more. +Skills for using the B2C CLI to manage your B2C Commerce instances. Covers code deployment, job execution, site archive import/export, WebDAV file operations, On-Demand Sandbox management, and more. Browse skills: [skills/b2c-cli/skills/](https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/tree/main/skills/b2c-cli/skills) diff --git a/docs/guide/analytics-reports-cip-ccac.md b/docs/guide/analytics-reports-cip-ccac.md index 839bd619..5156af6e 100644 --- a/docs/guide/analytics-reports-cip-ccac.md +++ b/docs/guide/analytics-reports-cip-ccac.md @@ -6,11 +6,11 @@ description: User guide for running CIP/CCAC analytics reports and SQL queries w The B2C CLI includes a `cip` command family for **B2C Commerce Intelligence (CIP)**, also known as **Commerce Cloud Analytics (CCAC)** reporting. -It is based on the **B2C Commerce Intelligence JDBC Driver** and gives you three practical workflows: +It’s based on the **B2C Commerce Intelligence JDBC Driver** and gives you three practical workflows. -- curated report commands (`b2c cip report `) for common analytics use cases -- raw SQL (`b2c cip query`) for custom exploration -- metadata discovery (`b2c cip tables`, `b2c cip describe`) for schema/table inspection +- Curated report commands (`b2c cip report `) for common analytics use cases +- Raw SQL (`b2c cip query`) for custom exploration +- Metadata discovery (`b2c cip tables`, `b2c cip describe`) for schema/table inspection Official JDBC reference: @@ -49,7 +49,7 @@ Starting with B2C Commerce release **26.1**, reports and dashboards data can als - Staging instances - Production instances in designated test realms (realms not serving live traffic) -To enable this, turn on **Enable Reports & Dashboards Data Tracking** in Business Manager feature switches. +To enable non-production support, turn on **Enable Reports & Dashboards Data Tracking** in Business Manager feature switches. - Reference: [Set Feature Switches (Toggles) in B2C Commerce](https://help.salesforce.com/s/articleView?id=cc.b2c_feature_switches.htm&type=5) - Provisioning can take up to **2 hours** after enabling @@ -194,10 +194,10 @@ Always check the official documentation before designing high-volume workloads. Practical guidance: -- prefer aggregate tables over large fact tables when possible -- avoid `SELECT *`; request only required columns -- keep date ranges narrow and run incremental windows -- test with smaller windows first, then scale up +- Prefer aggregate tables over large fact tables when possible. +- Avoid `SELECT *`; request only required columns. +- Keep date ranges narrow and run incremental windows. +- Test with smaller windows first, then scale up. Reference source for limits and best practices: diff --git a/docs/guide/authentication.md b/docs/guide/authentication.md index b1b5f17d..3a76c48c 100644 --- a/docs/guide/authentication.md +++ b/docs/guide/authentication.md @@ -53,9 +53,9 @@ For Account Manager operations that require user-level roles (organization and A ### Creating an API Client -1. Log in to [Account Manager](https://account.demandware.com) -2. Navigate to **API Client** in the left menu -3. Click **Add API Client** +1. Log in to [Account Manager](https://account.demandware.com). +2. Navigate to **API Client** in the left menu. +3. Click **Add API Client**. 4. Fill in the required fields: - **Display Name**: A descriptive name (e.g., "B2C CLI") - **Password**: A strong client secret (save this securely for Client Credentials auth) @@ -63,7 +63,7 @@ For Account Manager operations that require user-level roles (organization and A - `client_secret_basic` for client credentials flow ::: warning -The B2C CLI only supports `client_secret_basic` for the Token Endpoint Auth Method. `client_secret_post` and `private_key_jwt` are not currently supported. +The B2C CLI only supports `client_secret_basic` for the Token Endpoint Auth Method. `client_secret_post` and `private_key_jwt` aren't currently supported. ::: ### Assigning Roles @@ -76,16 +76,16 @@ Most roles require a **tenant filter** that specifies which tenants/realms the r | Role | Operations | Notes | | --------------------------------- | ----------------------------------------- | ------------------------------------------- | -| `Salesforce Commerce API` | SCAPI commands and CIP analytics commands | API Clients only. Requires tenant filter. | +| `Salesforce Commerce API` | SCAPI commands and CIP analytics commands | API clients only. Requires a tenant filter. | | `Sandbox API User` | ODS management, SLAS client management | Requires tenant filter with realm/org IDs. | -| `SLAS Organization Administrator` | SLAS client management (user auth only) | User accounts only. Requires tenant filter. | +| `SLAS Organization Administrator` | SLAS client management (user auth only) | User accounts only. Requires a tenant filter. | -#### For Client Credentials (roles on API Client) +#### For Client Credentials (Roles on API Client) Under the API Client's **Roles** section: 1. Add roles needed for your operations -2. For each role, configure the **tenant filter** with the tenant IDs (e.g., `zzxy_prd`) or realm IDs you need to access +2. For each role, configure the **tenant filter** with the tenant IDs (for example, `zzxy_prd`) or realm IDs you need to access **Important:** The `Salesforce Commerce API` role is currently only available for API Clients, not user accounts. @@ -122,8 +122,8 @@ See the individual CLI command pages for complete scope requirements. For ODS, SLAS, and SCAPI operations, your API client's roles must have a tenant filter configured: 1. In Account Manager, go to the API Client settings -2. Under each role (e.g., `Salesforce Commerce API`, `Sandbox API User`), find the **Tenant Filter** -3. Add the tenant IDs (e.g., `zzxy_prd`) or organization IDs you need to access +2. Under each role (for example, `Salesforce Commerce API`, `Sandbox API User`), find the **Tenant Filter** +3. Add the tenant IDs (for example, `zzxy_prd`) or organization IDs you need to access The tenant filter restricts which tenants/realms the role applies to. @@ -294,7 +294,7 @@ WebDAV is required for file upload operations (`code deploy`, `code watch`, `web ### Option A: Basic Authentication (Recommended) -Use your Business Manager username and a WebDAV access key. This provides better performance for file operations. +Use your Business Manager username and a WebDAV access key. These credentials provide better performance for file operations. 1. In Business Manager, go to **Administration** > **Organization** > **Users** 2. Select your user @@ -340,7 +340,7 @@ Common paths for CLI operations: | `/catalogs/` | Catalog file access | | `/libraries/` | Content library access | -**Note:** This configuration is only needed when using OAuth for WebDAV. It is not required when using basic authentication with username/access key. +**Note:** This configuration is only needed when using OAuth for WebDAV. It isn’t required when using basic authentication with username/access key. ## Managed Runtime API Key @@ -441,7 +441,7 @@ b2c scapi schemas list - Add the required scopes to your API client's Default Scopes - For SCAPI commands, ensure the relevant `sfcc.*` scopes are in Default Scopes -- Verify Default Scopes includes `mail roles tenantFilter openid` +- Verify that Default Scopes includes `mail roles tenantFilter openid` ## Next Steps diff --git a/docs/guide/ci-cd.md b/docs/guide/ci-cd.md index 60d1e30c..c2b81445 100644 --- a/docs/guide/ci-cd.md +++ b/docs/guide/ci-cd.md @@ -1,6 +1,6 @@ # CI/CD with GitHub Actions -The B2C Developer Tooling project provides official GitHub Actions for automating Commerce Cloud operations in your CI/CD pipelines. +The B2C Developer Tooling project provides official GitHub Actions for automating B2C Commerce operations in your CI/CD pipelines. ## Overview diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index c1553ba7..86333c57 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -85,7 +85,7 @@ You can configure the CLI using environment variables: ## .env File -The CLI automatically loads a `.env` file from the current working directory if present. Use the same `SFCC_*` variable names as environment variables. +The CLI automatically loads a `.env` file from the current project directory if present. Use the same `SFCC_*` variable names as environment variables. ```bash # .env diff --git a/docs/guide/ide-integration.md b/docs/guide/ide-integration.md index 1bf92bb8..ecde3ac0 100644 --- a/docs/guide/ide-integration.md +++ b/docs/guide/ide-integration.md @@ -8,7 +8,7 @@ This guide explains how to connect IDE extensions to your B2C CLI configuration. ## Prophet VS Code Extension -[Prophet](https://marketplace.visualstudio.com/items?itemName=SqrTT.prophet) can load `dw.json`-compatible configuration by executing a local `dw.js` script in your working directory. +[Prophet](https://marketplace.visualstudio.com/items?itemName=SqrTT.prophet) can load `dw.json`-compatible configuration by executing a local `dw.js` script in your project directory. ### Benefits @@ -60,14 +60,14 @@ function toProphetConfig(config) { function loadDwConfig() { try { - var workingDirectory = process.env.SFCC_PROJECT_DIRECTORY || process.env.SFCC_WORKING_DIRECTORY || __dirname || process.cwd(); + var projectDirectory = process.env.SFCC_PROJECT_DIRECTORY || process.env.SFCC_WORKING_DIRECTORY || __dirname || process.cwd(); var stdout = childProcess.execFileSync( 'b2c', - ['setup', 'inspect', '--json', '--unmask', '--project-directory', workingDirectory], + ['setup', 'inspect', '--json', '--unmask', '--project-directory', projectDirectory], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], - cwd: workingDirectory, + cwd: projectDirectory, }, ); diff --git a/docs/guide/index.md b/docs/guide/index.md index 4ced3541..9f1fd365 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -1,12 +1,15 @@ --- -description: Introduction to the B2C CLI and SDK for Salesforce Commerce Cloud B2C code deployment, site management, and sandbox operations. +description: Introduction to the B2C CLI, MCP Server, and SDK for Salesforce B2C Commerce code deployment, site management, and sandbox operations. --- # Introduction -The B2C CLI is a command-line interface for Salesforce Commerce Cloud B2C — deploy code, manage sandboxes, run jobs, and more from the terminal. +The B2C Developer Tooling provides command-line and AI-assisted development tools for Salesforce B2C Commerce. -## Quick Install +- **B2C CLI**: Command-line interface that you can use to deploy code, manage sandboxes, run jobs, and so on from the terminal. +- **MCP Server**: AI-assisted development tools for Cursor, Claude Desktop, and other AI assistants. + +## Quick CLI Install ::: code-group @@ -24,7 +27,39 @@ brew install SalesforceCommerceCloud/tools/b2c-cli ::: -See [Installation](./installation) for more options. +See the [CLI Installation Guide](./installation) for more installation options. + +## Quick MCP Install + +The B2C DX MCP Server enables AI assistants to help with B2C Commerce development tasks. Install it in your MCP client configuration: + +**Cursor** (supports `${workspaceFolder}`): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"] + } + } +} +``` + +**Claude Desktop** (use explicit path): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "/path/to/your/project", "--allow-non-ga-tools"] + } + } +} +``` + +See the [MCP Server Installation Guide](/mcp/installation) for detailed setup instructions. ## Next Steps @@ -32,5 +67,7 @@ See [Installation](./installation) for more options. - [Analytics Reports (CIP/CCAC)](./analytics-reports-cip-ccac) - Run curated analytics reports and SQL queries - [Configuration](./configuration) - Configure instances and credentials - [IDE Integration](./ide-integration) - Connect Prophet VS Code to B2C CLI configuration +- [MCP Server](/mcp/) - AI-assisted development with Model Context Protocol - [CLI Reference](/cli/) - Browse available commands +- [Tools Reference](/mcp/toolsets) - Explore MCP tools for cartridges, MRT, SCAPI, and so on - [API Reference](/api/) - Explore the SDK API diff --git a/docs/index.md b/docs/index.md index f83f7ad5..913fc586 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,5 @@ --- -description: Developer experience tools for Salesforce Commerce Cloud B2C - CLI, MCP Server, and SDK for AI-assisted development, deployment, and automation. +description: Developer experience tools for Salesforce B2C Commerce - CLI, MCP Server, and SDK for AI-assisted development, deployment, and automation. layout: home hero: @@ -16,6 +16,9 @@ hero: - theme: alt text: CLI Reference link: /cli/ + - theme: alt + text: MCP Server + link: /mcp/ - theme: alt text: API Reference link: /api/ @@ -43,8 +46,8 @@ features: linkText: Learn more - icon: "\U0001F916" title: AI-Assisted Development - details: MCP Server for Claude, Cursor, and other AI tools to interact with your B2C instances. (Coming Soon!) - link: /guide/ + details: MCP Server for Claude, Cursor, and other AI tools to interact with your B2C instances. + link: /mcp/ linkText: Learn more - icon: "\U0001F4E6" title: SDK Library diff --git a/docs/mcp/configuration.md b/docs/mcp/configuration.md new file mode 100644 index 00000000..45c1b835 --- /dev/null +++ b/docs/mcp/configuration.md @@ -0,0 +1,408 @@ +--- +description: Configure the B2C DX MCP Server with credentials, flags, environment variables, and toolset selection. +--- + +# Configuration + +The B2C DX MCP Server supports multiple configuration methods for credentials, flags, and toolset selection. + +## Configuration Priority + +Credentials are resolved in the following priority order. + +1. **Flags** (highest priority) +2. **Environment variables** +3. **Config files** (lowest priority) + +## Credential Sources + +### Option 1: Config Files (Recommended) + +Config files are the recommended approach for managing credentials. They keep credentials out of your MCP client configuration and are automatically loaded from your project. + +#### B2C Credentials (`dw.json`) + +Create a [`dw.json`](../guide/configuration#configuration-file) file in your project root: + +```json +{ + "hostname": "xxx.demandware.net", + "username": "...", + "password": "...", + "client-id": "...", + "client-secret": "..." +} +``` + +The server automatically loads this file when `--project-directory` points to your project. + +**Required fields per toolset:** + +| Toolset | Required Fields | +|---------|----------------| +| **SCAPI** | `hostname`, `client-id`, `client-secret` | +| **CARTRIDGES** | `hostname`, `username`, `password` (or OAuth) | +| **MRT** | (loaded from `~/.mobify`) | +| **PWAV3** | None (uses `--project-directory` only) | +| **STOREFRONTNEXT** | None (uses `--project-directory` only) | + +**Note:** Some tools require specific scopes. See [Configuring Scopes](../guide/authentication#configuring-scopes) in the Authentication Setup guide and individual tool pages for scope requirements. + +#### MRT Credentials (`~/.mobify`) + +Create a [`~/.mobify`](../guide/configuration#mobify-config-file) file in your home directory: + +```json +{ + "api_key": "..." +} +``` + +You can also create this file using the [B2C CLI](../cli/mrt#b2c-mrt-config-set): + +```bash +b2c mrt config set --api-key YOUR_API_KEY +``` + +### Option 2: Environment Variables + +Set environment variables in your MCP client configuration: + +**Cursor** (`.cursor/mcp.json`): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"], + "env": { + "SFCC_SERVER": "xxx.demandware.net", + "SFCC_USERNAME": "...", + "SFCC_PASSWORD": "...", + "SFCC_CLIENT_ID": "...", + "SFCC_CLIENT_SECRET": "...", + "SFCC_MRT_API_KEY": "..." + } + } + } +} +``` + +**Claude Desktop** (`claude_desktop_config.json`): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "/path/to/project", "--allow-non-ga-tools"], + "env": { + "SFCC_SERVER": "xxx.demandware.net", + "SFCC_USERNAME": "...", + "SFCC_PASSWORD": "..." + } + } + } +} +``` + +### Option 3: Flags + +Pass credentials directly as command-line flags: + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--server", + "xxx.demandware.net", + "--username", + "...", + "--password", + "...", + "--client-id", + "...", + "--client-secret", + "...", + "--allow-non-ga-tools" + ] + } + } +} +``` + +> **Note:** Flags are less secure than config files or environment variables, especially if your MCP client configuration is shared or committed to version control. + +## Flag Reference + +### Core Flags + +| Flag | Env Variable | Description | +|------|--------------|-------------| +| `--project-directory` | `SFCC_PROJECT_DIRECTORY` | Project directory (enables auto-discovery and config loading) | +| `--toolsets` | — | Comma-separated toolsets to enable | +| `--tools` | — | Comma-separated individual tools to enable | +| `--allow-non-ga-tools` | — | Enable experimental (non-GA) tools | +| `--config` | — | Explicit path to `dw.json` (advanced) | +| `--log-level` | — | Logging verbosity (trace, debug, info, warn, error, silent) | +| `--debug` | — | Enable debug logging | + +### B2C Instance Flags + +| Flag | Env Variable | Description | +|------|--------------|-------------| +| `--server` | `SFCC_SERVER` | B2C instance hostname | +| `--username` | `SFCC_USERNAME` | Username for Basic auth (WebDAV) | +| `--password` | `SFCC_PASSWORD` | Password/access key for Basic auth | +| `--client-id` | `SFCC_CLIENT_ID` | OAuth client ID | +| `--client-secret` | `SFCC_CLIENT_SECRET` | OAuth client secret | +| `--code-version` | `SFCC_CODE_VERSION` | Code version for deployments | + +### MRT Flags + +| Flag | Env Variable | Description | +|------|--------------|-------------| +| `--api-key` | `SFCC_MRT_API_KEY` | MRT API key | +| `--project` | `SFCC_MRT_PROJECT` | MRT project slug | +| `--environment` | `SFCC_MRT_ENVIRONMENT` | MRT environment (staging, production) | +| `--cloud-origin` | `SFCC_MRT_CLOUD_ORIGIN` | MRT cloud origin URL | + +## Toolset Selection + +### Auto-Discovery (Default) + +By default, the server automatically detects your project type and enables relevant toolsets. See [Project Type Detection](./installation#project-type-detection) for details. + +### Manual Selection + +Override auto-discovery by specifying toolsets explicitly: + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--toolsets", + "CARTRIDGES,MRT", + "--allow-non-ga-tools" + ] + } + } +} +``` + +**Available toolsets:** +- `CARTRIDGES` - Cartridge deployment and code version management +- `MRT` - Managed Runtime bundle operations +- `PWAV3` - PWA Kit v3 development tools +- `SCAPI` - Salesforce Commerce API discovery +- `STOREFRONTNEXT` - Storefront Next development tools +- `all` - Enable all toolsets + +**Note:** The `SCAPI` toolset is always enabled, even if not explicitly specified. + +### Individual Tool Selection + +Enable specific tools instead of entire toolsets: + +```json +{ + "args": [ + "--project-directory", + "${workspaceFolder}", + "--tools", + "cartridge_deploy,scapi_schemas_list", + "--allow-non-ga-tools" + ] +} +``` + +## Credential Details + +For authentication setup instructions, see the [Authentication Setup guide](../guide/authentication) which covers API client creation, WebDAV access, SCAPI authentication, and MRT API keys. + +### B2C Credentials + +#### Username/Password (WebDAV) + +- `username` - Your B2C Commerce username +- `password` - Your [WebDAV access key](https://help.salesforce.com/s/articleView?id=cc.b2c_account_manager_sso_use_webdav_file_access.htm&type=5) + +**Used by:** CARTRIDGES toolset + +See the [Authentication Setup guide](../guide/authentication#webdav-access) for detailed WebDAV access configuration. + +#### OAuth Client Credentials + +- `client-id` - API client ID from Account Manager +- `client-secret` - API client secret from Account Manager + +**Used by:** SCAPI toolset + +**Note:** Some tools require specific scopes. See [Configuring Scopes](../guide/authentication#configuring-scopes) in the Authentication Setup guide and individual tool pages for scope requirements. + +See the [Authentication Setup guide](../guide/authentication#account-manager-api-client) for creating and configuring API clients, and [SCAPI Authentication](../guide/authentication#scapi-authentication) for SCAPI-specific setup. + +### MRT Credentials + +- `api-key` - MRT API key from your Managed Runtime project +- `project` - MRT project slug (required) +- `environment` - MRT environment: `staging` or `production` (required when deploying) + +**Used by:** MRT toolset + +**Configuration location:** `~/.mobify` file + +See the [Authentication Setup guide](../guide/authentication#managed-runtime-api-key) for detailed MRT API key setup instructions. + +## Telemetry Configuration + +Telemetry is enabled by default. Configure it via environment variables: + +### Disable Telemetry + +```json +{ + "env": { + "SF_DISABLE_TELEMETRY": "true" + } +} +``` + +Or: + +```json +{ + "env": { + "SFCC_DISABLE_TELEMETRY": "true" + } +} +``` + +### Custom Telemetry Endpoint + +```json +{ + "env": { + "SFCC_APP_INSIGHTS_KEY": "your-key" + } +} +``` + +**Note:** Telemetry is automatically disabled when using `bin/dev.js` (development mode). + +## Logging Configuration + +### Log Level + +Set logging verbosity: + +```json +{ + "args": [ + "--log-level", + "debug" + ] +} +``` + +**Available levels:** `trace`, `debug`, `info`, `warn`, `error`, `silent` + +### Debug Mode + +Enable debug logging (equivalent to `--log-level debug`): + +```json +{ + "args": [ + "--debug" + ] +} +``` + +## Examples + +### Minimal Configuration (Auto-Discovery) + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--allow-non-ga-tools" + ] + } + } +} +``` + +Requires `dw.json` in project root for B2C credentials. + +### Full Configuration with Environment Variables + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--allow-non-ga-tools" + ], + "env": { + "SFCC_SERVER": "xxx.demandware.net", + "SFCC_CLIENT_ID": "...", + "SFCC_CLIENT_SECRET": "...", + "SFCC_MRT_API_KEY": "..." + } + } + } +} +``` + +### Manual Toolset Selection + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--toolsets", + "CARTRIDGES,SCAPI", + "--allow-non-ga-tools" + ] + } + } +} +``` + +## Next Steps + +- [Installation](./installation) - Set up the MCP server +- [Toolsets & Tools](./toolsets) - Explore available toolsets and tools +- [MCP Server Overview](./) - Learn more about the MCP server diff --git a/docs/mcp/index.md b/docs/mcp/index.md new file mode 100644 index 00000000..3cadd05d --- /dev/null +++ b/docs/mcp/index.md @@ -0,0 +1,169 @@ +--- +description: MCP Server for Salesforce B2C Commerce - AI-assisted development tools for Claude, Cursor, and other AI assistants. +--- + +# MCP Server + +The B2C DX MCP Server enables AI assistants (like Cursor, Claude Desktop, and others) to help with B2C Commerce development tasks. It provides toolsets for **SCAPI**, **CARTRIDGES**, **MRT**, **PWAV3**, and **STOREFRONTNEXT** development. + +> ⚠️ **Active Development**: This package is under active development. Some tools are currently **placeholder implementations** that return mock responses. Tool implementations will be added incrementally. + +## Overview + +The MCP server automatically detects your project type and enables relevant tools. It reads configuration from your project's configuration files and provides AI assistants with context-aware tools to help you: + +- Discover and explore Salesforce Commerce APIs (both standard and custom APIs). +- Deploy cartridges and manage code versions on your B2C instances. +- Build and deploy bundles to Managed Runtime for PWA Kit and Storefront Next projects. +- Get development guidelines and best practices for PWA Kit v3 and Storefront Next. +- Generate components, pages, and scaffold new features with framework-specific patterns. + +## Quick Start + +### Installation + +See the [Installation Guide](./installation) for detailed setup instructions for Cursor, Claude Desktop, and other MCP clients. + +**Cursor** (supports `${workspaceFolder}`): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"] + } + } +} +``` + +**Claude Desktop** (use explicit path): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "/path/to/your/project", "--allow-non-ga-tools"] + } + } +} +``` + +### Configuration + +The server automatically detects your project type and loads configuration from `dw.json` in your project root. See the [Configuration Guide](./configuration) for details on: + +- Credential management (config files, environment variables, flags) +- Project type detection +- Toolset selection (auto-discovery vs manual) +- Required credentials per toolset + +For authentication setup instructions, see the [Authentication Setup guide](../guide/authentication) which covers API client creation, WebDAV access, SCAPI authentication, and MRT API keys. + +### Available Toolsets + +The server provides five toolsets with specialized tools for different development workflows: + +- [CARTRIDGES](./toolsets#cartridges) - Cartridge deployment and code version management +- [MRT](./toolsets#mrt) - Managed Runtime bundle operations +- [PWAV3](./toolsets#pwav3) - PWA Kit v3 development tools +- [SCAPI](./toolsets#scapi) - Salesforce Commerce API discovery +- [STOREFRONTNEXT](./toolsets#storefrontnext) - Storefront Next development tools + +See the [Toolsets & Tools Reference](./toolsets) for detailed descriptions of each toolset and its tools. + +## Usage + +### Project Directory + +The most important flag is **`--project-directory`** (or env var `SFCC_PROJECT_DIRECTORY`). It tells the server where your project is located, enabling: + +1. **Auto-discovery** - Detects your project type and enables appropriate toolsets. +2. **Configuration loading** - Reads [`dw.json`](../guide/configuration#configuration-file) from your project for credentials. +3. **Scaffolding** - Creates new files in the correct location. + +> **Important:** MCP clients like Cursor and Claude Desktop spawn servers from the home directory (`~`), not your project. Always set `--project-directory`. + +### Project Type Detection + +The server analyzes your project directory and enables toolsets based on what it finds: + +| Project Type | Detection | Toolsets Enabled | +|--------------|-----------|------------------| +| **PWA Kit v3** | `@salesforce/pwa-kit-*`, `@salesforce/retail-react-app`, or `ccExtensibility` in package.json | PWAV3, MRT, SCAPI | +| **Storefront Next** | Root or a workspace package has `@salesforce/storefront-next*` dependency, or package name starting with `storefront-next`. | STOREFRONTNEXT, MRT, CARTRIDGES, SCAPI | +| **Cartridges** | `.project` file in cartridge directory | CARTRIDGES, SCAPI | +| **No project detected** | No B2C markers found | SCAPI (base toolset only) | + +The **SCAPI** toolset is always enabled. Hybrid projects (e.g., cartridges + PWA Kit) get combined toolsets. + +### Prompting Tips + +AI assistants automatically decide which MCP tools to use based on your prompts. To get the best results: + +> ⚠️ **IMPORTANT**: **Explicitly mention "Use the MCP tool"** in your prompts for reliable tool usage. While AI assistants can automatically select MCP tools based on context, explicit instructions ensure the assistant prioritizes MCP tools over general knowledge, especially when multiple approaches are possible. + +#### Best Practices + +1. **Always explicitly request MCP tool usage**: Start prompts with "Use the MCP tool to..." or include "Use the MCP tool" in your request +2. **Be specific about your goal**: Instead of "help me with Storefront Next", say "Use the MCP tool to show me how to build a product detail page with authentication" +3. **Mention the tool or domain explicitly**: Reference the framework (Storefront Next, PWA Kit), operation (deploy, discover), or domain (SCAPI, cartridges) +4. **Use natural language**: Describe what you want to achieve, not the tool name +5. **Provide context**: Mention your project type, what you're building, or what you need to learn +6. **Ask for guidelines first**: When starting a new project or learning a framework, ask for development guidelines before writing code +7. **Combine related topics**: Ask for multiple related sections in one request (e.g., "Use the MCP tool to show me data fetching and component patterns for Storefront Next") +8. **Specify operations clearly**: For deployment operations, mention the target and what to deploy (for example, "Use the MCP tool to deploy my cartridges to the sandbox instance") + +#### Example Prompts + +**Storefront Next Development:** +- ✅ "I'm new to Storefront Next. Use the MCP tool to show me the critical rules I need to know." +- ✅ "I need to build a product detail page. Use the MCP tool to show me best practices for data fetching and component patterns." + +**SCAPI Discovery:** +- ✅ "Use the MCP tool to list all available SCAPI schemas." +- ✅ "Use the MCP tool to get the OpenAPI schema for shopper-baskets v1." + +**Cartridge Deployment:** +- ✅ "Use the MCP tool to deploy my cartridges to the sandbox instance." + +**MRT Bundle Operations:** +- ✅ "Use the MCP tool to build and push my Storefront Next bundle to staging." + +See the [Toolsets & Tools Reference](./toolsets) for more prompting examples for each toolset. + +## Telemetry + +The MCP server collects anonymous usage telemetry to help improve the developer experience. Telemetry is enabled by default. + +**Development mode**: Telemetry is automatically disabled when using `bin/dev.js`, so local development and testing won't pollute production data. + +### Configuring Telemetry + +Set options in the `env` object of your server entry in `.cursor/mcp.json` or `~/.cursor/mcp.json`: + +- **Disable**: `SF_DISABLE_TELEMETRY=true` or `SFCC_DISABLE_TELEMETRY=true` +- **Custom endpoint**: `SFCC_APP_INSIGHTS_KEY=your-key` + +### What We Collect + +- **Server lifecycle events**: When the server starts, stops, or encounters errors +- **Tool usage**: Which tools are called and their execution time (not the arguments or results) +- **Command metrics**: Command duration and success/failure status +- **Environment info**: Platform, architecture, Node.js version, and package version + +### What We Don't Collect + +- **No credentials**: No API keys, passwords, or secrets +- **No business data**: No product data, customer information, or site content +- **No tool arguments**: No input parameters or output results from tool calls +- **No file contents**: No source code, configuration files, or project data + +## Next Steps + +- [Installation Guide](./installation) - Set up Cursor, Claude Desktop, or other MCP clients +- [Configuration](./configuration) - Configure credentials, flags, and toolset selection +- [Toolsets & Tools](./toolsets) - Explore available toolsets and tools +- [CLI Reference](../cli/) - Learn about the B2C CLI commands +- [API Reference](../api/) - Explore the SDK API diff --git a/docs/mcp/installation.md b/docs/mcp/installation.md new file mode 100644 index 00000000..ae50757f --- /dev/null +++ b/docs/mcp/installation.md @@ -0,0 +1,227 @@ +--- +description: Install and configure the B2C DX MCP Server for Cursor, Claude Desktop, and other MCP clients. +--- + +# Installation + +This guide covers installing and configuring the B2C DX MCP Server for various MCP clients. + +## Prerequisites + +- Node.js 22.0.0 or higher +- A B2C Commerce project (for project-specific toolsets) +- MCP client (Cursor, Claude Desktop, or compatible client) + +## Install via npm (Recommended) + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"] + } + } +} +``` + +## Cursor Configuration + +Cursor supports the `${workspaceFolder}` variable, which automatically resolves to your current workspace directory. + +### Setup Steps + +1. Open Cursor settings (Cmd/Ctrl + ,) +2. Search for "MCP" or navigate to MCP settings +3. Add the following configuration to `.cursor/mcp.json` (workspace) or `~/.cursor/mcp.json` (global): + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "${workspaceFolder}", + "--allow-non-ga-tools" + ] + } + } +} +``` + +4. Restart Cursor or reload the MCP server + +### Project Directory + +The `--project-directory` flag is critical. Cursor spawns MCP servers from your home directory (`~`), not your project directory. The `${workspaceFolder}` variable ensures the server knows where your project is located. + +**Why this matters:** +- Enables **auto-discovery** of your project type +- Loads configuration from `dw.json` in your project root +- Ensures that scaffolding creates files in the correct location + +## Claude Desktop Configuration + +Claude Desktop doesn't support workspace variables, so you must use an explicit path. + +### Setup Steps + +1. Open Claude Desktop settings +2. Navigate to MCP servers configuration (usually in `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS) +3. Add the following configuration: + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "/absolute/path/to/your/project", + "--allow-non-ga-tools" + ] + } + } +} +``` + +4. Replace path `/absolute/path/to/your/project` with actual absolute path to your B2C Commerce project. +5. Restart Claude Desktop. + +### Per-Project Configuration + +If you work with multiple projects, you can create separate MCP server entries for each: + +```json +{ + "mcpServers": { + "b2c-dx-project1": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "/path/to/project1", + "--allow-non-ga-tools" + ] + }, + "b2c-dx-project2": { + "command": "npx", + "args": [ + "-y", + "@salesforce/b2c-dx-mcp", + "--project-directory", + "/path/to/project2", + "--allow-non-ga-tools" + ] + } + } +} +``` + +## Project Directory Setup + +The `--project-directory` flag tells the server where your project is located. This enables: + +### 1. Auto-Discovery + +The server analyzes your project directory to detect the project type: + +| Project Type | Detection Criteria | +|--------------|-------------------| +| **PWA Kit v3** | `@salesforce/pwa-kit-*`, `@salesforce/retail-react-app`, or `ccExtensibility` in package.json | +| **Storefront Next** | Root or workspace package has `@salesforce/storefront-next*` dependency, or package name starting with `storefront-next` | +| **Cartridges** | `.project` file in cartridge directory | +| **No project detected** | No B2C markers found | + +Based on detection, the server automatically enables relevant toolsets. + +### 2. Configuration Loading + +The server reads [`dw.json`](../guide/configuration#configuration-file) from your project root for B2C credentials: + +```json +{ + "hostname": "xxx.demandware.net", + "username": "...", + "password": "...", + "client-id": "...", + "client-secret": "..." +} +``` + +See the [Authentication Setup guide](../guide/authentication) for detailed instructions on setting up API clients, WebDAV access, and SCAPI authentication. + +### 3. Scaffolding + +When creating new files (components, pages, cartridges), the server uses the project directory to place files in the correct location based on your project structure. + +## Project Type Detection + +The server automatically detects your project type by analyzing the project directory: + +### PWA Kit v3 + +Detected when: +- `package.json` contains `@salesforce/pwa-kit-*` dependencies +- `package.json` contains `@salesforce/retail-react-app` +- `package.json` contains `ccExtensibility` field + +**Enabled toolsets:** PWAV3, MRT, SCAPI + +### Storefront Next + +Detected when: +- Root `package.json` has `@salesforce/storefront-next*` dependency +- Any workspace package has `@salesforce/storefront-next*` dependency +- Package name starts with `storefront-next` + +**Enabled toolsets:** STOREFRONTNEXT, MRT, CARTRIDGES, SCAPI + +### Cartridges + +Detected when: +- A `.project` file exists in a cartridge directory + +**Enabled toolsets:** CARTRIDGES, SCAPI + +### No Project Detected + +If no B2C markers are found: +- Only the **SCAPI** toolset is enabled (base toolset) + +### Hybrid Projects + +Projects with multiple markers (e.g., cartridges + PWA Kit) get combined toolsets. For example: +- Cartridges + PWA Kit → CARTRIDGES, PWAV3, MRT, SCAPI + +## Troubleshooting + +### Server Not Starting + +- Verify Node.js version: `node --version` (must be 22.0.0+). +- Check that the path to `bin/dev.js` is correct and absolute. +- Ensure that the script is executable: `chmod +x bin/dev.js`. + +### Tools Not Available + +- Ensure `--allow-non-ga-tools` flag is included (required for placeholder tools). +- Check that `--project-directory` points to a valid project directory. +- Verify project type detection by checking your `package.json` or project structure. + +### Configuration Not Loading + +- Ensure `dw.json` exists in your project root +- Verify `--project-directory` points to the correct directory +- Check file permissions on `dw.json` + +## Next Steps + +- [Configuration](./configuration) - Configure credentials, flags, and toolset selection +- [Toolsets & Tools](./toolsets) - Explore available toolsets and tools +- [MCP Server Overview](./) - Learn more about the MCP server diff --git a/docs/mcp/tools/cartridge-deploy.md b/docs/mcp/tools/cartridge-deploy.md new file mode 100644 index 00000000..9d57d290 --- /dev/null +++ b/docs/mcp/tools/cartridge-deploy.md @@ -0,0 +1,101 @@ +--- +description: Deploy cartridges to a B2C Commerce instance via WebDAV with automatic code version reload. +--- + +# cartridge_deploy + +Deploys cartridges to a B2C Commerce instance via WebDAV. Finds cartridges by `.project` files, creates a ZIP archive, uploads via WebDAV, and optionally reloads the code version. + +## Overview + +The `cartridge_deploy` tool automates cartridge deployment to B2C Commerce instances. It: + +1. Searches the specified directory for cartridges (identified by `.project` files). +2. Applies the include/exclude filters to select which cartridges to deploy. +3. Creates a ZIP archive of all selected cartridge directories. +4. Uploads the ZIP to WebDAV and triggers server-side unzip. +5. Optionally reloads the code version after deployment. + +This tool is useful for deploying custom code cartridges for SFRA or other B2C Commerce code. It requires the instance to have a code version configured. + +## Authentication + +Supports two authentication methods: + +- **Basic Authentication (WebDAV)** - See [B2C Credentials](../configuration#b2c-credentials) (Username/Password section) +- **OAuth** - See [B2C Credentials](../configuration#b2c-credentials) (OAuth Client Credentials section) + +**Configuration Priority:** +1. Flags (`--server`, `--username`, `--password`, `--client-id`, `--client-secret`) +2. Environment variables (`SFCC_SERVER`, `SFCC_USERNAME`, `SFCC_PASSWORD`, `SFCC_CLIENT_ID`, `SFCC_CLIENT_SECRET`) +3. `dw.json` config file (auto-discovered or via `--config` flag) + +## Parameters + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `directory` | string | No | Project directory from `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` env var (falls back to process.cwd()) | Path to directory to search for cartridges. The tool recursively searches for `.project` files to identify cartridges. | +| `cartridges` | string[] | No | All found cartridges | Array of cartridge names to include in the deployment. Use this to selectively deploy specific cartridges when you have multiple cartridges but only want to update some. If not specified, all cartridges found in the directory are deployed. | +| `exclude` | string[] | No | None | Array of cartridge names to exclude from the deployment. Use this to skip deploying certain cartridges, such as third-party or unchanged cartridges. Applied after the include filter. | +| `reload` | boolean | No | `false` | Whether to reload the code version after deployment. When `true`, the tool triggers a code version reload on the instance. | + +## Usage Examples + +### Basic Deployment + +Deploy all cartridges found in the current directory: + +``` +Use the MCP tool to deploy my cartridges to the sandbox instance. +``` + +### Deploy Specific Cartridges + +Deploy only selected cartridges: + +``` +Use the MCP tool to deploy only the app_storefront_base cartridge to production. +``` + +### Deploy from Specific Directory + +Deploy cartridges from a specific directory: + +``` +Use the MCP tool to deploy cartridges from the ./cartridges directory and reload the code version. +``` + +### Exclude Cartridges + +Deploy all cartridges except certain ones: + +``` +Use the MCP tool to deploy cartridges excluding test_cartridge and bm_extensions. +``` + +## Output + +Returns a deployment result object containing: + +- `cartridges` - Array of cartridge mappings that were deployed (each with name, src, dest) +- `codeVersion` - Code version name used for deployment +- `reloaded` - Whether the code version was reloaded (if `reload: true`) + +## Requirements + +- B2C Commerce instance with WebDAV access +- Code version configured on the instance +- Cartridges must have `.project` files in their directories +- Valid authentication credentials (Basic auth or OAuth) + +## Related Tools + +- Part of the [CARTRIDGES](../toolsets#cartridges) toolset +- Auto-enabled for cartridge projects (detected by `.project` file) + +## See Also + +- [CARTRIDGES Toolset](../toolsets#cartridges) - Overview of cartridge development tools +- [Authentication Setup](../../guide/authentication) - Set up WebDAV access and OAuth credentials +- [Configuration](../configuration) - Configure credentials and instance settings +- [CLI Reference](../../cli/code) - Equivalent CLI command: `b2c code deploy` diff --git a/docs/mcp/tools/mrt-bundle-push.md b/docs/mcp/tools/mrt-bundle-push.md new file mode 100644 index 00000000..82de6203 --- /dev/null +++ b/docs/mcp/tools/mrt-bundle-push.md @@ -0,0 +1,112 @@ +--- +description: Build and push bundles to Managed Runtime for PWA Kit and Storefront Next deployments. +--- + +# mrt_bundle_push + +Creates a bundle from a pre-built PWA Kit or Storefront Next project and pushes it to Managed Runtime (MRT). Optionally deploys to a target environment after push. + +## Overview + +The `mrt_bundle_push` tool bundles a pre-built project and uploads it to Managed Runtime. It: + +1. Reads the build directory (default: `./build`). +2. Creates a bundle with server-only files (SSR) and shared files. +3. Pushes the bundle to Managed Runtime. +4. Optionally deploys to a target environment (staging or production). + +**Important:** The project must already be built (e.g., `npm run build` completed) before using this tool. + +This tool is shared across the MRT, PWAV3, and STOREFRONTNEXT toolsets. + +## Authentication + +Requires Managed Runtime (MRT) credentials. See [MRT Credentials](../configuration#mrt-credentials) for complete details. + +**Configuration priority:** +1. Flags (`--api-key`, `--project`, `--environment`) +2. Environment variables (`SFCC_MRT_API_KEY`, `SFCC_MRT_PROJECT`, `SFCC_MRT_ENVIRONMENT`) +3. `~/.mobify` config file (or `~/.mobify--[hostname]` if `--cloud-origin` is set) + +## Parameters + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `buildDirectory` | string | No | `./build` | Path to build directory containing the built project files. Can be absolute or relative to the project directory. | +| `message` | string | No | None | Deployment message to include with the bundle push. Useful for tracking deployments. | +| `ssrOnly` | string | No | `ssr.js,ssr.mjs,server/**/*` | Comma-separated glob patterns for server-only files (SSR). These files are only included in the server bundle. | +| `ssrShared` | string | No | `static/**/*,client/**/*` | Comma-separated glob patterns for shared files. These files are included in both server and client bundles. | +| `deploy` | boolean | No | `false` | Whether to deploy to an environment after push. When `true`, `environment` must be provided via `--environment` flag or `SFCC_MRT_ENVIRONMENT`. | + +## Usage Examples + +### Push Bundle Only + +Push a bundle without deploying: + +``` +Use the MCP tool to push the bundle from ./build directory to Managed Runtime. +``` + +### Push and Deploy to Staging + +Push a bundle and deploy to staging: + +``` +Use the MCP tool to build and push my Storefront Next bundle to staging. +``` + +### Push and Deploy to Production + +Push a bundle and deploy to production with a message: + +``` +Use the MCP tool to deploy my PWA Kit or Storefront Next bundle to production with a deployment message. +``` + +### Custom Build Directory + +Push from a custom build directory: + +``` +Use the MCP tool to push the bundle from ./dist directory to Managed Runtime. +``` + +## Output + +Returns a push result object containing: + +- `bundleId` - Unique identifier for the pushed bundle +- `projectSlug` - MRT project slug +- `target` - Target environment (if deployed) +- `deployed` - Whether the bundle was deployed (if `deploy: true`) +- `message` - Deployment message (if provided) + +## Requirements + +- Pre-built project (run `npm run build` or equivalent first) +- MRT API key configured +- MRT project slug configured +- Valid build directory with required files + +## Error Handling + +The tool throws an error if: + +- `project` isn’t provided (required) +- `deploy: true` but `environment` isn’t provided +- Build directory doesn’t exist or is invalid +- MRT API authentication fails +- Bundle push fails + +## Related Tools + +- Part of the [MRT](../toolsets#mrt), [PWAV3](../toolsets#pwav3), and [STOREFRONTNEXT](../toolsets#storefrontnext) toolsets +- Auto-enabled for PWA Kit v3 and Storefront Next projects + +## See Also + +- [MRT Toolset](../toolsets#mrt) - Overview of Managed Runtime tools +- [Authentication Setup](../../guide/authentication#managed-runtime-api-key) - Set up MRT API key +- [Configuration](../configuration) - Configure MRT credentials +- [CLI Reference](../../cli/mrt) - Equivalent CLI command: `b2c mrt bundle push` diff --git a/docs/mcp/tools/scapi-custom-apis-status.md b/docs/mcp/tools/scapi-custom-apis-status.md new file mode 100644 index 00000000..d8b9ec90 --- /dev/null +++ b/docs/mcp/tools/scapi-custom-apis-status.md @@ -0,0 +1,201 @@ +--- +description: Check the registration status of custom SCAPI endpoints deployed on your B2C Commerce instance. +--- + +# scapi_custom_apis_status + +List custom SCAPI endpoint registration status (active/not_registered). Returns one row per endpoint per site with detailed status information. + +## Overview + +The `scapi_custom_apis_status` tool checks the registration status of custom API endpoints deployed on your B2C Commerce instance. It: + +- Returns individual HTTP endpoints (for example, `GET /hello`, `POST /items/{id}`). +- Shows registration status: `active` or `not_registered`. +- Provides per-site details (one row per endpoint per site). +- Supports filtering, grouping, and column selection. + +**Important:** This tool is **remote only** - it queries your live instance. For schema definitions, use [`scapi_schemas_list`](./scapi-schemas-list) with `apiFamily: "custom"`. + +## Authentication + +Requires OAuth credentials. See [B2C Credentials](../configuration#b2c-credentials) (OAuth Client Credentials section) for complete details. + +**Required scope:** `sfcc.custom-apis` + +**Configuration priority:** +1. Flags (`--server`, `--client-id`, `--client-secret`) +2. Environment variables (`SFCC_SERVER`, `SFCC_CLIENT_ID`, `SFCC_CLIENT_SECRET`) +3. `dw.json` config file + +**Note:** Instance configuration (shortCode, tenantId) is also required and is auto-detected from credentials. + +## Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `status` | `"active"` \| `"not_registered"` | No | Filter by endpoint status. Omit to return all endpoints. | +| `groupBy` | `"site"` \| `"type"` | No | Group output by `siteId` or `type` (Admin/Shopper). Omit for flat list. | +| `columns` | string | No | Comma-separated field names to include. Omit for defaults (7 fields). Use all field names for complete data. | + +### Available Columns + +**Default columns (7 fields):** +- `type` - API type (Admin/Shopper) +- `apiName` - Custom API name +- `cartridgeName` - Cartridge containing the endpoint +- `endpointPath` - Endpoint path (for example, `/hello`) +- `httpMethod` - HTTP method (GET, POST, and so on) +- `status` - Registration status (active/not_registered) +- `siteId` - Site ID + +**All available fields:** +- `type`, `apiName`, `apiVersion`, `cartridgeName`, `endpointPath`, `httpMethod`, `status`, `siteId`, `securityScheme`, `operationId`, `schemaFile`, `implementationScript`, `errorReason`, `id` + +## Usage Examples + +### List All Endpoints + +List all custom API endpoints: + +``` +Use the MCP tool to list custom SCAPI endpoints on my instance. +``` + +### Filter by Status + +Show only active endpoints: + +``` +Use the MCP tool to list only active custom API endpoints. +``` + +Find endpoints that failed to register: + +``` +Use the MCP tool to find custom API endpoints that failed to register. +``` + +### Group by Site + +Group endpoints by site: + +``` +Use the MCP tool to list custom API endpoints grouped by site. +``` + +### Group by Type + +Group endpoints by API type (Admin/Shopper): + +``` +Use the MCP tool to list custom API endpoints grouped by type. +``` + +### Custom Columns + +Show specific fields: + +``` +Use the MCP tool to show only apiName and status for active endpoints. +``` + +Show all fields: + +``` +Use the MCP tool to show endpoint details with all fields. +``` + +## Output + +### Default Output + +Returns endpoints with 7 default fields: + +```json +{ + "endpoints": [ + { + "type": "Shopper", + "apiName": "loyalty-points", + "cartridgeName": "app_custom", + "endpointPath": "/hello", + "httpMethod": "GET", + "status": "active", + "siteId": "RefArch" + } + ], + "total": 1, + "activeCodeVersion": "v1.0.0", + "timestamp": "2025-01-01T00:00:00.000Z" +} +``` + +### Grouped Output + +When `groupBy` is set, returns grouped structure: + +```json +{ + "groups": { + "RefArch": [...], + "SiteGenesis": [...] + }, + "total": 5, + "activeCodeVersion": "v1.0.0", + "timestamp": "2025-01-01T00:00:00.000Z" +} +``` + +### Error Output + +On authentication or API errors: + +```json +{ + "total": 0, + "activeCodeVersion": null, + "remoteError": "Failed to fetch remote endpoints: ...", + "message": "Failed to fetch Custom API endpoints: ...", + "timestamp": "2025-01-01T00:00:00.000Z" +} +``` + +## Use Cases + +- **Verify deployment**: Check if custom API endpoints are properly registered +- **Troubleshoot registration failures**: Find endpoints with `not_registered` status +- **Per-site analysis**: See which endpoints are active for each site +- **API type filtering**: Distinguish between Admin and Shopper APIs + +## Requirements + +- OAuth credentials with `sfcc.custom-apis` scope +- B2C Commerce instance hostname +- Instance configuration (shortCode, tenantId) - auto-detected +- Custom APIs deployed on the instance + +## Error Handling + +The tool returns a `remoteError` field if: + +- OAuth authentication fails +- `sfcc.custom-apis` scope is missing +- Instance configuration is invalid +- API request fails + +Check the `message` field for detailed error information. + +## Related Tools + +- Part of the [SCAPI](../toolsets#scapi), [PWAV3](../toolsets#pwav3), and [STOREFRONTNEXT](../toolsets#storefrontnext) toolsets +- Always enabled (base toolset) +- For schema definitions, use [`scapi_schemas_list`](./scapi-schemas-list) with `apiFamily: "custom"` + +## See Also + +- [SCAPI Toolset](../toolsets#scapi) - Overview of SCAPI discovery tools +- [scapi_schemas_list](./scapi-schemas-list) - List and fetch SCAPI schemas +- [Authentication Setup](../../guide/authentication#scapi-authentication) - Set up SCAPI authentication with required roles and scopes +- [Configuration](../configuration) - Configure OAuth credentials +- [CLI Reference](../../cli/custom-apis) - Equivalent CLI command: `b2c scapi custom status` diff --git a/docs/mcp/tools/scapi-schemas-list.md b/docs/mcp/tools/scapi-schemas-list.md new file mode 100644 index 00000000..961df486 --- /dev/null +++ b/docs/mcp/tools/scapi-schemas-list.md @@ -0,0 +1,169 @@ +--- +description: List or fetch SCAPI schema metadata and OpenAPI specs for standard and custom APIs. +--- + +# scapi_schemas_list + +List or fetch SCAPI schema metadata and OpenAPI specs for standard SCAPI (Shop/Admin/Shopper) and custom APIs. Supports both discovery (list mode) and detailed schema fetching. + +## Overview + +The `scapi_schemas_list` tool provides two modes of operation. + +1. **List (Discovery)**: Browse available schemas without fetching full OpenAPI specs. +2. **Fetch**: Retrieve complete OpenAPI schema for a specific API. + +This tool works with both standard SCAPI (Shop, Admin, Shopper APIs) and custom APIs. For endpoint registration status, use [`scapi_custom_apis_status`](./scapi-custom-apis-status) instead. + +## Authentication + +Requires OAuth credentials. See [B2C Credentials](../configuration#b2c-credentials) (OAuth Client Credentials section) for complete details. + +**Required scope:** `sfcc.scapi-schemas` (required for fetch mode) + +**Note:** OAuth credentials are optional for local schema discovery (list mode), but required for fetching full schemas. + +**Configuration priority:** +1. Flags (`--server`, `--client-id`, `--client-secret`) +2. Environment variables (`SFCC_SERVER`, `SFCC_CLIENT_ID`, `SFCC_CLIENT_SECRET`) +3. `dw.json` config file + +## Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `apiFamily` | string | No | Filter by API family (for example, `"shopper"`, `"product"`, `"checkout"`, `"custom"`). Use `"custom"` for custom APIs. | +| `apiName` | string | No | Filter by API name (for example, `"shopper-products"`, `"shopper-baskets"`). | +| `apiVersion` | string | No | Filter by API version (for example, `"v1"`, `"v2"`). | +| `status` | `"current"` \| `"deprecated"` | No | Filter by schema status. Use `"current"` for active schemas, `"deprecated"` for phased-out schemas. Only works in list mode. | +| `includeSchemas` | boolean | No | Include full OpenAPI schemas. Requires all three: `apiFamily`, `apiName`, and `apiVersion`. | +| `expandAll` | boolean | No | Return the full schema without collapsing. Only works when `includeSchemas: true`. | + +## Operation Modes + +### List Mode (Discovery) + +Omit `includeSchemas` or any identifier to browse available schemas: + +**Returns:** +- `schemas` - Array of schema metadata +- `total` - Total number of schemas found +- `availableApiFamilies` - List of available API families +- `availableApiNames` - List of available API names +- `availableApiVersions` - List of available API versions + +**Example prompts:** +- ✅ "Use the MCP tool to list all available SCAPI schemas." +- ✅ "Use the MCP tool to show me what checkout APIs exist." → `apiFamily: "checkout"` +- ✅ "Use the MCP tool to discover SCAPI product endpoints." → `apiFamily: "product"` +- ✅ "Use the MCP tool to list custom API definitions." → `apiFamily: "custom"` + +### Fetch Mode + +Set `includeSchemas: true` and provide all three identifiers (`apiFamily`, `apiName`, `apiVersion`) to fetch a complete OpenAPI schema: + +**Returns:** +- Full OpenAPI schema specification +- Use `expandAll: true` to get the complete schema without collapsing + +**Example prompts:** +- ✅ "Use the MCP tool to get the OpenAPI schema for shopper-baskets v1." → `apiFamily: "shopper"`, `apiName: "shopper-baskets"`, `apiVersion: "v1"`, `includeSchemas: true` +- ✅ "Use the MCP tool to show me the full OpenAPI spec for shopper-products v1." → `includeSchemas: true`, `expandAll: true` +- ✅ "Use the MCP tool to show me the loyalty-points custom API schema." → `apiFamily: "custom"`, `apiName: "loyalty-points"`, `apiVersion: "v1"`, `includeSchemas: true` + +## Usage Examples + +### Standard SCAPI Discovery + +List all available SCAPI schemas: + +``` +Use the MCP tool to list all available SCAPI schemas. +``` + +Filter by API family: + +``` +Use the MCP tool to show me what checkout APIs exist. +``` + +### Custom API Discovery + +List custom API definitions: + +``` +Use the MCP tool to list custom API definitions. +``` + +Fetch a specific custom API schema: + +``` +Use the MCP tool to show me the loyalty-points custom API schema. +``` + +### Fetch Full Schema + +Get complete OpenAPI specification: + +``` +Use the MCP tool to get the OpenAPI schema for shopper-baskets v1. +``` + +Get expanded schema without collapsing: + +``` +Use the MCP tool to show me the full OpenAPI spec for shopper-products v1. +``` + +## Rules and Constraints + +- `includeSchemas` requires all three identifiers: `apiFamily`, `apiName`, and `apiVersion` +- `status` only works in list mode (discovery) +- Custom APIs use `apiFamily: "custom"` +- `expandAll` only works when `includeSchemas: true` + +## Output + +### List Mode Output + +```json +{ + "schemas": [...], + "total": 42, + "availableApiFamilies": ["shopper", "admin", "shop"], + "availableApiNames": ["shopper-products", "shopper-baskets", ...], + "availableApiVersions": ["v1", "v2"], + "timestamp": "2025-01-01T00:00:00.000Z" +} +``` + +### Fetch Mode Output + +```json +{ + "openapi": "3.0.0", + "info": {...}, + "paths": {...}, + "components": {...} +} +``` + +## Requirements + +- OAuth credentials with `sfcc.scapi-schemas` scope (for fetch mode) +- B2C Commerce instance hostname +- Organization ID (auto-detected from credentials) + +## Related Tools + +- Part of the [SCAPI](../toolsets#scapi), [PWAV3](../toolsets#pwav3), and [STOREFRONTNEXT](../toolsets#storefrontnext) toolsets +- Always enabled (base toolset) +- For endpoint registration status, use [`scapi_custom_apis_status`](./scapi-custom-apis-status) + +## See Also + +- [SCAPI Toolset](../toolsets#scapi) - Overview of SCAPI discovery tools +- [scapi_custom_apis_status](./scapi-custom-apis-status) - Check custom API endpoint registration status +- [Authentication Setup](../../guide/authentication#scapi-authentication) - Set up SCAPI authentication with required roles and scopes +- [Configuration](../configuration) - Configure OAuth credentials +- [CLI Reference](../../cli/scapi-schemas) - Equivalent CLI commands: `b2c scapi schemas list` and `b2c scapi schemas get` diff --git a/docs/mcp/tools/storefront-next-page-designer-decorator.md b/docs/mcp/tools/storefront-next-page-designer-decorator.md new file mode 100644 index 00000000..6a4586d1 --- /dev/null +++ b/docs/mcp/tools/storefront-next-page-designer-decorator.md @@ -0,0 +1,227 @@ +--- +description: Add Page Designer decorators to React components for Storefront Next to make them available in Page Designer. +--- + +# storefront_next_page_designer_decorator + +Adds Page Designer decorators (`@Component`, `@AttributeDefinition`, `@RegionDefinition`) to React components to make them available in Page Designer for Storefront Next. + +## Overview + +The `storefront_next_page_designer_decorator` tool analyzes React components and generates Page Designer decorators that enable components to be used in Page Designer. It supports two modes: + +1. **Auto Mode**: Quick setup with sensible defaults-automatically selects suitable props, infers types, and generates decorators immediately. +2. **Interactive Mode**: Multi-step workflow for fine-tuned control over decorator configuration. + +The tool uses component discovery to find components by name (e.g., "ProductCard") without requiring exact file paths, making it easy to add Page Designer support to existing components. + +## Authentication + +No authentication required. This tool operates on local files only. + +**Requirements:** +- `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` environment variable (for component discovery) +- Storefront Next project with React components + +## Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `component` | string | Yes | Component name (for example, `"ProductCard"`, `"Hero"`) or file path (for example, `"src/components/ProductCard.tsx"`). When a name is provided, the tool automatically searches common component directories. | +| `searchPaths` | string[] | No | Additional directories to search for components (for example, `["packages/retail/src", "app/features"]`). Only used when a component is specified by name (not path). | +| `autoMode` | boolean | No | Auto-generate all configurations with sensible defaults (skip interactive workflow). When enabled, automatically selects suitable props, infers types, and generates decorators without user confirmation. | +| `componentId` | string | No | Override component ID (default: auto-generated from component name). | +| `conversationContext` | object | No | Context for interactive mode workflow. See [Interactive Mode](#interactive-mode) for details. | + +### Conversation Context (Interactive Mode) + +When using interactive mode, provide `conversationContext` with the following structure: + +| Field | Type | Description | +|-------|------|-------------| +| `step` | `"analyze"` \| `"select_props"` \| `"configure_attrs"` \| `"configure_regions"` \| `"confirm_generation"` | Current step in the conversation workflow | +| `componentInfo` | object | Cached component analysis from previous step | +| `selectedProps` | string[] | Props from component interface selected to expose in Page Designer | +| `newAttributes` | object[] | New attributes to add (not in existing props) | +| `attributeConfig` | object | Configuration for each attribute (explicit types, names, defaults, etc.) | +| `componentMetadata` | object | Component decorator configuration (id, name, description, group) | +| `regionConfig` | object | Region configuration (enabled, regions array) | + +## Operation Modes + +### Auto Mode + +Auto mode generates decorators immediately with sensible defaults: + +- Automatically selects suitable props (excludes complex types, UI-only props) +- Infers types from TypeScript interfaces +- Generates decorator code without user confirmation + +**Usage:** + +``` +Use the MCP tool to add Page Designer decorators to my ProductCard component with auto mode. +``` + +**Example:** + +```json +{ + "component": "ProductCard", + "autoMode": true +} +``` + +### Interactive Mode + +Interactive mode provides a multi-step workflow for fine-tuned control: + +1. **Analyze** (`step: "analyze"`) - Analyze component and review props +2. **Select Props** (`step: "select_props"`) - Choose which props to expose +3. **Configure Attributes** (`step: "configure_attrs"`) - Configure types, defaults, and values +4. **Configure Regions** (`step: "configure_regions"`) - Configure nested content areas +5. **Confirm Generation** (`step: "confirm_generation"`) - Generate final decorator code + +**Usage:** + +``` +Use the MCP tool to add Page Designer decorators to my Hero component interactively. +``` + +**Example:** + +```json +{ + "component": "Hero", + "conversationContext": { + "step": "analyze" + } +} +``` + +## Component Discovery + +The tool automatically searches for components in these locations (in order): + +1. `src/components/**` (PascalCase and kebab-case) +2. `app/components/**` +3. `components/**` +4. `src/**` (broader search) +5. Custom paths (if provided via `searchPaths`) + +**Project Directory:** +Component discovery uses the project directory resolved from `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` environment variable. This ensures searches start from the correct project directory, especially when MCP clients spawn servers from the home directory. + +**Examples:** + +- `"ProductCard"` → finds `src/components/product-tile/ProductCard.tsx` +- `"Hero"` → finds `src/components/hero/Hero.tsx` or `app/components/hero.tsx` +- `"product-card"` → finds `src/components/product-card.tsx` or `product-card/index.tsx` + +**Tips:** + +- Use component name for portability +- Use path for unusual locations +- Add `searchPaths` for monorepos or non-standard structures +- Ensure `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` env var is set correctly + +## Usage Examples + +### Basic Auto Mode + +Add Page Designer support with auto-generated defaults: + +``` +Use the MCP tool to add Page Designer decorators to my ProductCard component. +``` + +### Auto Mode with Custom Search Paths + +Search in custom directories: + +``` +Use the MCP tool to add Page Designer decorators to ProductCard, searching in packages/retail/src and app/features. +``` + +### Interactive Mode - Start Analysis + +Begin interactive workflow: + +``` +Use the MCP tool to analyze my Hero component for Page Designer decorators. +``` + +### Path-Based Usage + +Specify exact component path: + +``` +Use the MCP tool to add Page Designer decorators to src/components/ProductCard.tsx with auto mode. +``` + +## Output + +The tool returns generated decorator code that includes: + +- **Imports**: Required Page Designer decorator imports +- **@Component Decorator**: Component metadata (id, name, description, group) +- **@AttributeDefinition Decorators**: Attribute definitions for each prop +- **@RegionDefinition Decorator**: Region definitions (if configured) + +**Example Output:** + +```typescript +import { Component, AttributeDefinition, RegionDefinition } from '@salesforce/page-designer'; + +@Component({ + id: 'product-card', + name: 'Product Card', + description: 'Displays product information', + group: 'Commerce' +}) +export class ProductCardMetadata { + @AttributeDefinition({ + id: 'product-id', + name: 'Product ID', + type: 'string', + required: true + }) + productId: string; + + @AttributeDefinition({ + id: 'show-price', + name: 'Show Price', + type: 'boolean', + defaultValue: true + }) + showPrice: boolean; +} +``` + +## Requirements + +- Storefront Next project +- React component with TypeScript interfaces +- `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` environment variable set +- Component must be discoverable in standard directories or via `searchPaths` + +## Features + +- **Name-Based Lookup**: Find components by name without knowing paths +- **Auto-Discovery**: Automatically searches common component directories +- **Type-Safe**: Full TypeScript type inference for all contexts +- **Fast**: Direct function execution, no file I/O or compilation overhead +- **Flexible Input**: Supports component names or file paths +- **Two Modes**: Auto mode for quick setup, Interactive mode for fine-tuned control + +## Related Tools + +- Part of the [STOREFRONTNEXT](../toolsets#storefrontnext) toolset +- Auto-enabled for Storefront Next projects +- Related: [`storefront_next_generate_page_designer_metadata`](../toolsets#storefrontnext) - Generate Page Designer metadata + +## See Also + +- [STOREFRONTNEXT Toolset](../toolsets#storefrontnext) - Overview of Storefront Next development tools +- [Configuration](../configuration) - Configure project directory +- [Storefront Next Guide](../../guide/storefront-next) - Storefront Next development guide diff --git a/docs/mcp/toolsets.md b/docs/mcp/toolsets.md new file mode 100644 index 00000000..b7b20a7e --- /dev/null +++ b/docs/mcp/toolsets.md @@ -0,0 +1,122 @@ +--- +description: Available toolsets and tools in the B2C DX MCP Server for SCAPI, CARTRIDGES, MRT, PWAV3, and STOREFRONTNEXT development. +--- + +# Toolsets & Tools + +The B2C DX MCP Server provides five toolsets with specialized tools for different B2C Commerce development workflows. + +> **Note:** Some tools are currently placeholder or early release implementations. Use `--allow-non-ga-tools` flag to enable them. + +## Overview + +Toolsets are collections of related tools that work together to support specific development workflows. The server automatically enables toolsets based on your project type, or you can manually select toolsets using the `--toolsets` flag. + +**Available toolsets:** +- [CARTRIDGES](#cartridges) - Cartridge deployment and code version management +- [MRT](#mrt) - Managed Runtime bundle operations +- [PWAV3](#pwav3) - PWA Kit v3 development tools +- [SCAPI](#scapi) - Salesforce Commerce API discovery +- [STOREFRONTNEXT](#storefrontnext) - Storefront Next development tools + +**Note:** The `SCAPI` toolset is always enabled, even if not explicitly specified. + +## CARTRIDGES + +Cartridge development, deployment, and code version management. + +**Status:** 🚧 Early Access + +**Auto-enabled for:** Cartridge projects (detected by `.project` file) + +### Tools + +| Tool | Description | Documentation | +|------|-------------|---------------| +| [`cartridge_deploy`](./tools/cartridge-deploy) | Deploy cartridges to a B2C Commerce instance | [View details](./tools/cartridge-deploy) | + +## MRT + +Managed Runtime operations for PWA Kit and Storefront Next deployments. + +**Status:** 🚧 Early Access + +**Auto-enabled for:** PWA Kit v3 and Storefront Next projects + +### Tools + +| Tool | Description | Documentation | +|------|-------------|---------------| +| [`mrt_bundle_push`](./tools/mrt-bundle-push) | Build, push bundle (optionally deploy) | [View details](./tools/mrt-bundle-push) | + +## PWAV3 + +PWA Kit v3 development tools for building headless storefronts. + +**Status:** 🚧 Placeholder + +**Auto-enabled for:** PWA Kit v3 projects (detected by `@salesforce/pwa-kit-*` dependencies) + +### Tools + +| Tool | Description | Documentation | +|------|-------------|---------------| +| `pwakit_create_storefront` | Create a new PWA Kit storefront project | — | +| `pwakit_create_page` | Create a new page component in the PWA Kit project | — | +| `pwakit_create_component` | Create a React component in the PWA Kit project | — | +| `pwakit_get_dev_guidelines` | Get PWA Kit development guidelines and best practices | — | +| `pwakit_recommend_hooks` | Recommend appropriate React hooks for PWA Kit use cases | — | +| `pwakit_run_site_test` | Run site tests for PWA Kit project | — | +| `pwakit_install_agent_rules` | Install AI agent rules for PWA Kit development | — | +| [`scapi_schemas_list`](./tools/scapi-schemas-list) | List or fetch SCAPI schemas (standard and custom). Use apiFamily: "custom" for custom APIs. | [View details](./tools/scapi-schemas-list) | +| [`scapi_custom_apis_status`](./tools/scapi-custom-apis-status) | Get registration status of custom API endpoints (active/not_registered). Remote only, requires OAuth. | [View details](./tools/scapi-custom-apis-status) | +| [`mrt_bundle_push`](./tools/mrt-bundle-push) | Build, push bundle (optionally deploy) | [View details](./tools/mrt-bundle-push) | + +## SCAPI + +Salesforce Commerce API discovery and exploration. + +**Status:** 🚧 Early Access + +**Always enabled** - Base toolset available for all projects. + +### Tools + +| Tool | Description | Documentation | +|------|-------------|---------------| +| [`scapi_schemas_list`](./tools/scapi-schemas-list) | List or fetch SCAPI schemas (standard and custom). Use apiFamily: "custom" for custom APIs. | [View details](./tools/scapi-schemas-list) | +| [`scapi_custom_apis_status`](./tools/scapi-custom-apis-status) | Get registration status of custom API endpoints (active/not_registered). Remote only, requires OAuth. | [View details](./tools/scapi-custom-apis-status) | +| `scapi_customapi_scaffold` | Scaffold a new custom SCAPI API (not yet implemented) | — | + +## STOREFRONTNEXT + +Storefront Next development tools for building modern storefronts. + +**Status:** 🚧 Placeholder + +**Auto-enabled for:** Storefront Next projects (detected by `@salesforce/storefront-next*` dependencies) + +### Tools + +| Tool | Description | Documentation | +|------|-------------|---------------| +| `storefront_next_development_guidelines` | Get Storefront Next development guidelines and best practices | — | +| `storefront_next_site_theming` | Configure and manage site theming for Storefront Next | — | +| `storefront_next_figma_to_component_workflow` | Convert Figma designs to Storefront Next components | — | +| `storefront_next_generate_component` | Generate a new Storefront Next component | — | +| `storefront_next_map_tokens_to_theme` | Map design tokens to Storefront Next theme configuration | — | +| [`storefront_next_page_designer_decorator`](./tools/storefront-next-page-designer-decorator) | Add Page Designer decorators to Storefront Next components | [View details](./tools/storefront-next-page-designer-decorator) | +| `storefront_next_generate_page_designer_metadata` | Generate Page Designer metadata for Storefront Next components | — | +| [`scapi_schemas_list`](./tools/scapi-schemas-list) | List or fetch SCAPI schemas (standard and custom). Use apiFamily: "custom" for custom APIs. | [View details](./tools/scapi-schemas-list) | +| [`scapi_custom_apis_status`](./tools/scapi-custom-apis-status) | Get registration status of custom API endpoints (active/not_registered). Remote only, requires OAuth. | [View details](./tools/scapi-custom-apis-status) | +| [`mrt_bundle_push`](./tools/mrt-bundle-push) | Build, push bundle (optionally deploy) | [View details](./tools/mrt-bundle-push) | + +## Tool Deduplication + +Some tools appear in multiple toolsets (for example, `mrt_bundle_push`, `scapi_schemas_list`, `scapi_custom_apis_status`). When using multiple toolsets, tools are automatically deduplicated, so you'll only see each tool once. + +## Next Steps + +- [Configuration](./configuration) - Configure credentials and toolset selection +- [Installation](./installation) - Set up the MCP server +- [MCP Server Overview](./) - Learn more about the MCP server diff --git a/package.json b/package.json index d2cf9221..e64e4954 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/b2c-cli-root", + "description": "Salesforce B2C Commerce Command Line Tools", "version": "0.0.1-preview", - "description": "Salesforce Commerce Cloud B2C Command Line Tools", "main": "index.js", "scripts": { "start": "pnpm --filter @salesforce/b2c-cli run dev", diff --git a/packages/b2c-cli/package.json b/packages/b2c-cli/package.json index 0c31fa1c..abed01b4 100644 --- a/packages/b2c-cli/package.json +++ b/packages/b2c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@salesforce/b2c-cli", - "description": "A Salesforce Commerce Cloud B2C CLI", + "description": "A Salesforce B2C Commerce CLI", "version": "0.5.2", "author": "Charles Lavery", "bin": { diff --git a/packages/b2c-cli/src/commands/setup/ide/prophet.ts b/packages/b2c-cli/src/commands/setup/ide/prophet.ts index 0842f0e4..c7f7f9c8 100644 --- a/packages/b2c-cli/src/commands/setup/ide/prophet.ts +++ b/packages/b2c-cli/src/commands/setup/ide/prophet.ts @@ -89,12 +89,12 @@ function getWorkspaceRoot() { return process.cwd(); } -function withWorkingDirectory(args, workingDirectory) { - if (!workingDirectory || args.indexOf('--project-directory') !== -1 || args.indexOf('--working-directory') !== -1) { +function withProjectDirectory(args, projectDirectory) { + if (!projectDirectory || args.indexOf('--project-directory') !== -1 || args.indexOf('--working-directory') !== -1) { return args.slice(); } - return args.concat(['--project-directory', workingDirectory]); + return args.concat(['--project-directory', projectDirectory]); } function pickInspectConfig(parsed) { @@ -115,8 +115,8 @@ function pickInspectConfig(parsed) { return root; } -function runSetupInspect(workingDirectory) { - var inspectArgs = withWorkingDirectory(INSPECT_ARGS, workingDirectory); +function runSetupInspect(projectDirectory) { + var inspectArgs = withProjectDirectory(INSPECT_ARGS, projectDirectory); var candidates = []; if (process.env.B2C_CLI_BIN && process.env.B2C_CLI_BIN.trim()) { @@ -135,8 +135,8 @@ function runSetupInspect(workingDirectory) { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], }; - if (workingDirectory) { - execOptions.cwd = workingDirectory; + if (projectDirectory) { + execOptions.cwd = projectDirectory; } var stdout = childProcess.execFileSync(candidate.cmd, candidate.args, execOptions); @@ -174,11 +174,11 @@ function resolveDwJsonConfig(raw) { return raw; } -function loadDwJsonFallback(workingDirectory) { +function loadDwJsonFallback(projectDirectory) { try { - var dwJsonPath = process.env.SFCC_CONFIG ? process.env.SFCC_CONFIG : path.join(workingDirectory, 'dw.json'); + var dwJsonPath = process.env.SFCC_CONFIG ? process.env.SFCC_CONFIG : path.join(projectDirectory, 'dw.json'); if (!path.isAbsolute(dwJsonPath)) { - dwJsonPath = path.resolve(workingDirectory || process.cwd(), dwJsonPath); + dwJsonPath = path.resolve(projectDirectory || process.cwd(), dwJsonPath); } return resolveDwJsonConfig(require(dwJsonPath)); @@ -227,10 +227,10 @@ function toProphetConfig(config) { function loadDwConfig() { loadDotEnv(); - var workingDirectory = getWorkspaceRoot(); + var projectDirectory = getWorkspaceRoot(); try { - var inspectConfig = runSetupInspect(workingDirectory); + var inspectConfig = runSetupInspect(projectDirectory); var inspectMapped = toProphetConfig(inspectConfig); if (inspectMapped.hostname) { return inspectMapped; @@ -242,7 +242,7 @@ function loadDwConfig() { } try { - var fallbackMapped = toProphetConfig(loadDwJsonFallback(workingDirectory)); + var fallbackMapped = toProphetConfig(loadDwJsonFallback(projectDirectory)); if (!fallbackMapped.hostname) { logProphetDw('dw.json fallback returned no hostname'); } diff --git a/packages/b2c-cli/test/commands/setup/ide/prophet.test.ts b/packages/b2c-cli/test/commands/setup/ide/prophet.test.ts index db937569..f74180d4 100644 --- a/packages/b2c-cli/test/commands/setup/ide/prophet.test.ts +++ b/packages/b2c-cli/test/commands/setup/ide/prophet.test.ts @@ -93,9 +93,9 @@ describe('setup ide prophet', () => { expect(content).to.include('process.env.SFCC_WORKING_DIRECTORY'); expect(content).to.include('try {'); expect(content).to.include('return {};'); - expect(content).to.include('execOptions.cwd = workingDirectory;'); - expect(content).to.include("path.join(workingDirectory, 'dw.json')"); - expect(content).to.include('path.resolve(workingDirectory || process.cwd(), dwJsonPath);'); + expect(content).to.include('execOptions.cwd = projectDirectory;'); + expect(content).to.include("path.join(projectDirectory, 'dw.json')"); + expect(content).to.include('path.resolve(projectDirectory || process.cwd(), dwJsonPath);'); expect(content).to.include('return resolveDwJsonConfig(require(dwJsonPath));'); expect(content).to.include('setup inspect returned no hostname; falling back to dw.json'); expect(content).to.include('dw.json fallback returned no hostname'); diff --git a/packages/b2c-dx-mcp/CONTRIBUTING.md b/packages/b2c-dx-mcp/CONTRIBUTING.md new file mode 100644 index 00000000..e963d6f0 --- /dev/null +++ b/packages/b2c-dx-mcp/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# Contributing to B2C DX MCP + +For general contributing guidelines, see the [root CONTRIBUTING.md](../../CONTRIBUTING.md). + +## Development Build (Local) + +For local development or testing, use the development build directly: + +```json +{ + "mcpServers": { + "b2c-dx": { + "command": "node", + "args": ["/path/to/packages/b2c-dx-mcp/bin/dev.js", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"] + } + } +} +``` + +Replace `/path/to/packages/b2c-dx-mcp/bin/dev.js` with the actual path to your cloned repository. + +## Testing the MCP Server Locally + +### MCP Inspector + +Use MCP Inspector to browse tools and test them in a web UI: + +```bash +cd packages/b2c-dx-mcp +pnpm run inspect:dev +``` + +This runs TypeScript directly (no build needed). Open the localhost URL shown in the terminal, click **Connect**, then **List Tools** to see available tools. + +### IDE Integration + +Configure your IDE to use the local MCP server. Add this to your IDE's MCP configuration: + +```json +{ + "mcpServers": { + "b2c-dx-local": { + "command": "node", + "args": [ + "/full/path/to/packages/b2c-dx-mcp/bin/dev.js", + "--toolsets", "all", + "--allow-non-ga-tools" + ] + } + } +} +``` + +> **Note:** When developing the B2C DX MCP package (`packages/b2c-dx-mcp`), use `node` with the path to `bin/dev.js` in args. Build to latest (`pnpm run build` from the repo root) so changes that require a rebuild are reflected when you run the server. +> +> **Note:** Make sure the script is executable: `chmod +x /full/path/to/packages/b2c-dx-mcp/bin/dev.js` +> +> **Note:** Restart the MCP server in your IDE to pick up code changes. diff --git a/packages/b2c-dx-mcp/README.md b/packages/b2c-dx-mcp/README.md index b2edb7fa..bc2368ca 100644 --- a/packages/b2c-dx-mcp/README.md +++ b/packages/b2c-dx-mcp/README.md @@ -1,8 +1,8 @@ -# Salesforce Commerce Cloud B2C MCP Server +# Salesforce B2C Commerce MCP Server -MCP (Model Context Protocol) server for Salesforce B2C Commerce Cloud developer experience tools. +MCP (Model Context Protocol) server for Salesforce B2C Commerce developer experience tools. -> ⚠️ **Active Development**: This package is under active development. All tools are currently **placeholder implementations** that return mock responses. Tool implementations will be added incrementally. +> ⚠️ **Active Development**: This package is under active development. Some tools are currently **placeholder implementations** that return mock responses. Tool implementations will be added incrementally. ## Overview @@ -12,15 +12,15 @@ The server automatically detects your project type and enables relevant tools. S ## Usage -### Working Directory and Auto-Discovery +### Project Directory and Auto-Discovery -The most important flag is **`--working-directory`** (or env var `SFCC_WORKING_DIRECTORY`). It tells the server where your project is located, enabling: +The most important flag is **`--project-directory`** (or env var `SFCC_PROJECT_DIRECTORY`). It tells the server where your project is located, enabling: 1. **Auto-discovery** - Detects your project type and enables appropriate toolsets 2. **Configuration loading** - Reads [`dw.json`](https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/configuration.html#configuration-file) from your project for credentials 3. **Scaffolding** - Creates new files in the correct location -> **Important:** MCP clients like Cursor and Claude Desktop spawn servers from the home directory (`~`), not your project. Always set `--working-directory`. +> **Important:** MCP clients like Cursor and Claude Desktop spawn servers from the home directory (`~`), not your project. Always set `--project-directory`. **Cursor** (supports `${workspaceFolder}`): @@ -29,7 +29,7 @@ The most important flag is **`--working-directory`** (or env var `SFCC_WORKING_D "mcpServers": { "b2c-dx": { "command": "npx", - "args": ["-y", "@salesforce/b2c-dx-mcp", "--working-directory", "${workspaceFolder}", "--allow-non-ga-tools"] + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "${workspaceFolder}", "--allow-non-ga-tools"] } } } @@ -42,7 +42,7 @@ The most important flag is **`--working-directory`** (or env var `SFCC_WORKING_D "mcpServers": { "b2c-dx": { "command": "npx", - "args": ["-y", "@salesforce/b2c-dx-mcp", "--working-directory", "/path/to/your/project", "--allow-non-ga-tools"] + "args": ["-y", "@salesforce/b2c-dx-mcp", "--project-directory", "/path/to/your/project", "--allow-non-ga-tools"] } } } @@ -50,7 +50,7 @@ The most important flag is **`--working-directory`** (or env var `SFCC_WORKING_D ### Project Type Detection -The server analyzes your working directory and enables toolsets based on what it finds: +The server analyzes your project directory and enables toolsets based on what it finds: | Project Type | Detection | Toolsets Enabled | |--------------|-----------|------------------| @@ -66,14 +66,14 @@ The **SCAPI** toolset is always enabled. Hybrid projects (e.g., cartridges + PWA Override auto-discovery by specifying toolsets explicitly: ```json -"args": ["--working-directory", "${workspaceFolder}", "--toolsets", "CARTRIDGES,MRT", "--allow-non-ga-tools"] +"args": ["--project-directory", "${workspaceFolder}", "--toolsets", "CARTRIDGES,MRT", "--allow-non-ga-tools"] ``` ### Prompting Tips and Examples AI assistants (like Cursor, Claude Desktop) automatically decide which MCP tools to use based on your prompts. To get the best results, use clear, specific prompts that describe what you want to accomplish. -> ⚠️ **IMPORTANT**: **Explicitly mention "Use the MCP tool"** in your prompts for reliable tool usage. While AI assistants (like Cursor's Composer) can automatically select MCP tools based on context, explicit instructions ensure the assistant prioritizes MCP tools over general knowledge, especially when multiple approaches are possible. This is particularly important for getting project-specific, up-to-date information rather than generic responses. +> ⚠️ **IMPORTANT**: **Explicitly mention "Use the MCP tool"** in your prompts for reliable tool usage. While AI assistants (like Cursor's Composer) can automatically select MCP tools based on context, explicit instructions ensure that the assistant prioritizes MCP tools over general knowledge, especially when multiple approaches are possible. This is particularly important for getting project-specific, up-to-date information rather than generic responses. #### Best Practices @@ -90,7 +90,7 @@ AI assistants (like Cursor, Claude Desktop) automatically decide which MCP tools The `storefront_next_development_guidelines` tool provides critical architecture rules and best practices. **Use this tool first** when starting new Storefront Next development or when you need architecture guidance. -**Good prompts:** +**Prompt examples:** - ✅ "I'm new to Storefront Next. Use the MCP tool to show me the critical rules I need to know." - ✅ "I need to build a product detail page. Use the MCP tool to show me best practices for data fetching and component patterns." - ✅ "I need to build a checkout form with authentication and validation. Use the MCP tool to show me how to handle form submissions, authentication, and internationalized error messages." @@ -114,7 +114,7 @@ The `storefront_next_development_guidelines` tool provides critical architecture ##### PWA Kit Development -**Good prompts:** +**Prompt examples:** - ✅ "I'm starting a new PWA Kit project. Use the MCP tool to get the development guidelines." - ✅ "Use the MCP tool to create a new product listing page component in my PWA Kit project." - ✅ "Use the MCP tool to recommend React hooks for fetching product data in PWA Kit." @@ -153,14 +153,14 @@ Get registration status of custom API endpoints deployed on the instance (remote ##### Cartridge Deployment -**Good prompts:** +**Prompt examples:** - ✅ "Use the MCP tool to deploy my cartridges to the sandbox instance." - ✅ "Use the MCP tool to deploy only the app_storefront_base cartridge to production." - ✅ "Use the MCP tool to deploy cartridges from the ./cartridges directory and reload the code version." ##### MRT Bundle Operations -**Good prompts:** +**Prompt examples:** - ✅ "Use the MCP tool to build and push my Storefront Next bundle to staging." - ✅ "Use the MCP tool to push the bundle from ./build directory to Managed Runtime." - ✅ "Use the MCP tool to deploy my PWA Kit or Storefront Next bundle to production with a deployment message." @@ -181,8 +181,8 @@ Credentials can be provided via **config files** (recommended), **environment va | **SCAPI** | `hostname` + `client-id` + `client-secret` (for `scapi_custom_apis_status`: requires `sfcc.custom-apis` scope) | | **CARTRIDGES** | `hostname` + `username` + `password` (or OAuth) | | **MRT** | `api-key` + `project` (optionally `environment`) | -| **PWAV3** | `--working-directory` only (+ MRT config for deployments) | -| **STOREFRONTNEXT** | `--working-directory` only (+ MRT/CARTRIDGES config for those tools) | +| **PWAV3** | `--project-directory` only (+ MRT config for deployments) | +| **STOREFRONTNEXT** | `--project-directory` only (+ MRT/CARTRIDGES config for those tools) | **Option 1: Config files (recommended)** @@ -220,7 +220,7 @@ See [Flag Reference](#flag-reference) for all available flags and env vars. | Flag | Env Variable | Description | |------|--------------|-------------| -| `--working-directory` | `SFCC_WORKING_DIRECTORY` | Project directory (enables auto-discovery and config loading) | +| `--project-directory` | `SFCC_PROJECT_DIRECTORY` | Project directory (enables auto-discovery and config loading) | | `--toolsets` | — | Comma-separated toolsets to enable | | `--tools` | — | Comma-separated individual tools to enable | | `--allow-non-ga-tools` | — | Enable experimental (non-GA) tools | @@ -378,7 +378,7 @@ pnpm run lint pnpm run clean ``` -### Working Directory +### Project Directory Commands should be run from the `packages/b2c-dx-mcp` directory: @@ -435,7 +435,7 @@ Configure your IDE to use the local MCP server. Add this to your IDE's MCP confi } ``` -> **Note:** Make sure the script is executable: `chmod +x /full/path/to/packages/b2c-dx-mcp/bin/dev.js` +> **Note:** Make sure that the script is executable: `chmod +x /full/path/to/packages/b2c-dx-mcp/bin/dev.js` > > The script's shebang (`#!/usr/bin/env -S node --conditions development`) handles Node.js setup automatically. diff --git a/packages/b2c-dx-mcp/package.json b/packages/b2c-dx-mcp/package.json index 82bb8a15..82cb178e 100644 --- a/packages/b2c-dx-mcp/package.json +++ b/packages/b2c-dx-mcp/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/b2c-dx-mcp", + "description": "MCP server for B2C Commerce developer experience tools", "version": "0.4.2", - "description": "MCP server for B2C Commerce Cloud developer experience tools", "author": "Salesforce", "license": "MIT", "repository": "SalesforceCommerceCloud/b2c-developer-tooling", diff --git a/packages/b2c-dx-mcp/src/commands/mcp.ts b/packages/b2c-dx-mcp/src/commands/mcp.ts index 72db95a0..1f541ea5 100644 --- a/packages/b2c-dx-mcp/src/commands/mcp.ts +++ b/packages/b2c-dx-mcp/src/commands/mcp.ts @@ -8,7 +8,7 @@ * MCP Server Command - Salesforce B2C Commerce Developer Experience * * This is the main entry point for the B2C DX MCP server, built with oclif. - * It exposes B2C Commerce Cloud developer tools to AI assistants via the + * It exposes B2C Commerce developer tools to AI assistants via the * Model Context Protocol (MCP). * * ## Flags @@ -164,7 +164,7 @@ import {TOOLSETS, type StartupFlags} from '../utils/index.js'; */ export default class McpServerCommand extends BaseCommand { static description = - 'Salesforce B2C Commerce Cloud Developer Experience MCP Server - Expose B2C Commerce Developer Experience tools to AI assistants'; + 'Salesforce B2C Commerce Developer Experience MCP Server - Expose B2C Commerce Developer Experience tools to AI assistants'; static examples = [ { @@ -326,8 +326,8 @@ export default class McpServerCommand extends BaseCommand s.trim()) : undefined, allowNonGaTools: this.flags['allow-non-ga-tools'], configPath: this.flags.config, - // Working directory for auto-discovery. oclif handles flag with env fallback. - workingDirectory: this.flags['project-directory'], + // Project directory for auto-discovery. oclif handles flag with env fallback. + projectDirectory: this.flags['project-directory'], }; // Add toolsets to telemetry attributes diff --git a/packages/b2c-dx-mcp/src/registry.ts b/packages/b2c-dx-mcp/src/registry.ts index 7d2be4fa..a87d9bc4 100644 --- a/packages/b2c-dx-mcp/src/registry.ts +++ b/packages/b2c-dx-mcp/src/registry.ts @@ -111,27 +111,27 @@ export function createToolRegistry(loadServices: () => Services): ToolRegistry { * Performs workspace auto-discovery and returns appropriate toolsets. * Always includes BASE_TOOLSET even if no project types are detected. * - * @param flags - Startup flags containing workingDirectory + * @param flags - Startup flags containing projectDirectory * @param reason - Reason for triggering auto-discovery (for logging) * @returns Array of toolsets to enable */ async function performAutoDiscovery(flags: StartupFlags, reason: string): Promise { const logger = getLogger(); - // Working directory from --project-directory flag or SFCC_PROJECT_DIRECTORY env var - const workingDirectory = flags.workingDirectory ?? process.cwd(); + // Project directory from --project-directory flag or SFCC_PROJECT_DIRECTORY env var + const projectDirectory = flags.projectDirectory ?? process.cwd(); - // Warn if working directory wasn't explicitly configured - if (!flags.workingDirectory) { + // Warn if project directory wasn't explicitly configured + if (!flags.projectDirectory) { logger.warn( - {cwd: workingDirectory}, + {cwd: projectDirectory}, 'No --project-directory flag or SFCC_PROJECT_DIRECTORY env var provided. ' + 'MCP clients like Cursor and Claude Desktop often spawn servers from ~ instead of the project directory. ' + 'Set --project-directory or SFCC_PROJECT_DIRECTORY for reliable auto-discovery.', ); } - const detectionResult = await detectWorkspaceType(workingDirectory); + const detectionResult = await detectWorkspaceType(projectDirectory); // Map all detected project types to MCP toolsets (union) // Note: getToolsetsForProjectTypes always includes BASE_TOOLSET diff --git a/packages/b2c-dx-mcp/src/services.ts b/packages/b2c-dx-mcp/src/services.ts index 4a3d617a..c785d351 100644 --- a/packages/b2c-dx-mcp/src/services.ts +++ b/packages/b2c-dx-mcp/src/services.ts @@ -314,16 +314,16 @@ export class Services { } /** - * Get the project working directory. + * Get the project project directory. * Falls back to process.cwd() if not explicitly set. * * This is the directory where the project is located, which may differ from process.cwd() * when MCP clients spawn servers from a different location (e.g., home directory). * - * @returns Project working directory path + * @returns Project project directory path */ public getWorkingDirectory(): string { - return this.resolvedConfig.values.workingDirectory ?? process.cwd(); + return this.resolvedConfig.values.projectDirectory ?? process.cwd(); } /** diff --git a/packages/b2c-dx-mcp/src/tools/cartridges/index.ts b/packages/b2c-dx-mcp/src/tools/cartridges/index.ts index e5e61eb3..a0bfff4c 100644 --- a/packages/b2c-dx-mcp/src/tools/cartridges/index.ts +++ b/packages/b2c-dx-mcp/src/tools/cartridges/index.ts @@ -79,7 +79,7 @@ function createCartridgeDeployTool(loadServices: () => Services, injections?: Ca .string() .optional() .describe( - 'Path to directory to search for cartridges. Defaults to current working directory if not specified. ' + + 'Path to directory to search for cartridges. Defaults to current project directory if not specified. ' + 'The tool will recursively search this directory for .project files to identify cartridges.', ), cartridges: z @@ -128,7 +128,7 @@ function createCartridgeDeployTool(loadServices: () => Services, injections?: Ca instance.config.codeVersion = codeVersion; } - // Resolve directory path: relative paths are resolved relative to working directory, absolute paths are used as-is + // Resolve directory path: relative paths are resolved relative to project directory, absolute paths are used as-is const directory = args.directory ? path.isAbsolute(args.directory) ? args.directory diff --git a/packages/b2c-dx-mcp/src/tools/storefrontnext/README.md b/packages/b2c-dx-mcp/src/tools/storefrontnext/README.md index cf45a994..f9624521 100644 --- a/packages/b2c-dx-mcp/src/tools/storefrontnext/README.md +++ b/packages/b2c-dx-mcp/src/tools/storefrontnext/README.md @@ -196,9 +196,9 @@ The tool automatically searches for components in these locations (in order): 4. `src/**` (broader search) 5. Custom paths (if provided via `searchPaths`) -**Working Directory**: +**Project Directory**: -Component discovery uses the working directory resolved from `--working-directory` flag or `SFCC_WORKING_DIRECTORY` environment variable (via Services). This ensures searches start from the correct project directory, especially when MCP clients spawn servers from the home directory. +Component discovery uses the project directory resolved from `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` environment variable (via Services). This ensures searches start from the correct project directory, especially when MCP clients spawn servers from the home directory. **See also**: [Detailed documentation](./page-designer-decorator/README.md) for complete usage guide, architecture details, and examples. diff --git a/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/README.md b/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/README.md index fbacf655..d828a732 100644 --- a/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/README.md +++ b/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/README.md @@ -90,8 +90,8 @@ The tool automatically searches for components in these locations (in order): 4. `src/**` (broader search) 5. Custom paths (if provided via `searchPaths`) -**Working Directory:** -Component discovery uses the working directory resolved from `--working-directory` flag or `SFCC_WORKING_DIRECTORY` environment variable (via Services). This ensures searches start from the correct project directory, especially when MCP clients spawn servers from the home directory. +**Project Directory:** +Component discovery uses the project directory resolved from `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` environment variable (via Services). This ensures searches start from the correct project directory, especially when MCP clients spawn servers from the home directory. **Examples:** @@ -104,7 +104,7 @@ Component discovery uses the working directory resolved from `--working-director - Use component name for portability - Use path for unusual locations - Add `searchPaths` for monorepos or non-standard structures -- Ensure `--working-directory` flag or `SFCC_WORKING_DIRECTORY` env var is set correctly +- Ensure `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` env var is set correctly ## 🏗️ Architecture @@ -247,7 +247,7 @@ The test suite covers: - Interactive mode (all steps: analyze, select_props, configure_attrs, configure_regions, confirm_generation) - Error handling (invalid input, invalid step name, missing parameters) - Edge cases (no props, only complex props, optional props, union types, already decorated components) -- Working directory resolution (from --working-directory flag or SFCC_WORKING_DIRECTORY env var via Services) +- Project directory resolution (from `--project-directory` flag or `SFCC_PROJECT_DIRECTORY` env var via Services) See [`test/tools/storefrontnext/page-designer-decorator/README.md`](../../../../test/tools/storefrontnext/page-designer-decorator/README.md) for detailed testing instructions. diff --git a/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/index.ts b/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/index.ts index 649873a4..8ccb2a9b 100644 --- a/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/index.ts +++ b/packages/b2c-dx-mcp/src/tools/storefrontnext/page-designer-decorator/index.ts @@ -634,7 +634,7 @@ export function createPageDesignerDecoratorTool(loadServices: () => Services): M description: 'Adds Page Designer decorators (@Component, @AttributeDefinition, @RegionDefinition) to React components. ' + 'Two modes: autoMode=true for quick setup with defaults, or interactive mode via conversationContext.step. ' + - 'Component discovery uses workingDirectory from flags/env. ' + + 'Component discovery uses projectDirectory from flags/env. ' + 'Auto mode: selects suitable props, infers types, generates code immediately. ' + 'Interactive mode: multi-step workflow (analyze → select_props → configure_attrs → configure_regions → confirm_generation).', @@ -646,7 +646,7 @@ export function createPageDesignerDecoratorTool(loadServices: () => Services): M try { // Validate and parse input const validatedArgs = pageDesignerDecoratorSchema.parse(args) as PageDesignerDecoratorInput; - // Use workingDirectory from services to ensure we search in the correct project directory + // Use projectDirectory from services to ensure we search in the correct project directory // This prevents searches in the home folder when MCP clients spawn servers from ~ const services = loadServices(); const workspaceRoot = services.getWorkingDirectory(); diff --git a/packages/b2c-dx-mcp/src/utils/types.ts b/packages/b2c-dx-mcp/src/utils/types.ts index 254be6ac..84c6c788 100644 --- a/packages/b2c-dx-mcp/src/utils/types.ts +++ b/packages/b2c-dx-mcp/src/utils/types.ts @@ -50,6 +50,6 @@ export interface StartupFlags { allowNonGaTools?: boolean; /** Path to config file (dw.json format) */ configPath?: string; - /** Project working directory for tools (auto-discovery, scaffolding, etc.) */ - workingDirectory?: string; + /** Project project directory for tools (auto-discovery, scaffolding, etc.) */ + projectDirectory?: string; } diff --git a/packages/b2c-dx-mcp/test/commands/mcp.test.ts b/packages/b2c-dx-mcp/test/commands/mcp.test.ts index c8304b4a..adc6d67d 100644 --- a/packages/b2c-dx-mcp/test/commands/mcp.test.ts +++ b/packages/b2c-dx-mcp/test/commands/mcp.test.ts @@ -495,7 +495,7 @@ describe('McpServerCommand', () => { // Stub getBaseConfigOptions sandbox.stub(command as unknown as Record, 'getBaseConfigOptions').returns({ configPath: undefined, - workingDirectory: process.cwd(), + projectDirectory: process.cwd(), }); // Call loadConfiguration via protected access diff --git a/packages/b2c-dx-mcp/test/registry.test.ts b/packages/b2c-dx-mcp/test/registry.test.ts index a8c41fb1..c46e57f5 100644 --- a/packages/b2c-dx-mcp/test/registry.test.ts +++ b/packages/b2c-dx-mcp/test/registry.test.ts @@ -136,7 +136,7 @@ describe('registry', () => { const server = createMockServer(); // Use a workspace path that won't match any patterns (should fall back to SCAPI) const flags: StartupFlags = { - workingDirectory: '/nonexistent/path', + projectDirectory: '/nonexistent/path', allowNonGaTools: true, }; @@ -359,10 +359,10 @@ describe('registry', () => { }); describe('auto-discovery', () => { - it('should use workingDirectory from flags for detection', async () => { + it('should use projectDirectory from flags for detection', async () => { const server = createMockServer(); const flags: StartupFlags = { - workingDirectory: '/some/workspace', + projectDirectory: '/some/workspace', allowNonGaTools: true, }; @@ -378,7 +378,7 @@ describe('registry', () => { // Use a path that doesn't exist - detection will return 'unknown' project type // which maps to SCAPI toolset const flags: StartupFlags = { - workingDirectory: '/nonexistent', + projectDirectory: '/nonexistent', allowNonGaTools: true, }; @@ -393,7 +393,7 @@ describe('registry', () => { const server = createMockServer(); const flags: StartupFlags = { tools: ['cartridge_deploy'], - workingDirectory: '/some/workspace', + projectDirectory: '/some/workspace', allowNonGaTools: true, }; @@ -409,7 +409,7 @@ describe('registry', () => { const server = createMockServer(); const flags: StartupFlags = { toolsets: ['CARTRIDGES'], - workingDirectory: '/some/workspace', + projectDirectory: '/some/workspace', allowNonGaTools: true, }; diff --git a/packages/b2c-dx-mcp/test/services.test.ts b/packages/b2c-dx-mcp/test/services.test.ts index 77b2b100..c3013396 100644 --- a/packages/b2c-dx-mcp/test/services.test.ts +++ b/packages/b2c-dx-mcp/test/services.test.ts @@ -173,9 +173,9 @@ describe('services', () => { }); describe('getWorkingDirectory', () => { - it('should return working directory when provided in config', () => { + it('should return project directory when provided in config', () => { const workingDir = '/path/to/project'; - const config = createMockResolvedConfig({workingDirectory: workingDir}); + const config = createMockResolvedConfig({projectDirectory: workingDir}); const services = new Services({resolvedConfig: config}); expect(services.getWorkingDirectory()).to.equal(workingDir); @@ -188,12 +188,12 @@ describe('services', () => { expect(services.getWorkingDirectory()).to.equal(process.cwd()); }); - it('should return working directory from fromResolvedConfig when provided in config', () => { - const workingDir = '/path/to/project'; - const config = createMockResolvedConfig({workingDirectory: workingDir}); + it('should return project directory from fromResolvedConfig when provided in config', () => { + const projectDir = '/path/to/project'; + const config = createMockResolvedConfig({projectDirectory: projectDir}); const services = Services.fromResolvedConfig(config); - expect(services.getWorkingDirectory()).to.equal(workingDir); + expect(services.getWorkingDirectory()).to.equal(projectDir); }); it('should fall back to process.cwd() from fromResolvedConfig when not provided in config', () => { diff --git a/packages/b2c-dx-mcp/test/tools/cartridges/index.test.ts b/packages/b2c-dx-mcp/test/tools/cartridges/index.test.ts index 6236a175..e6a640a7 100644 --- a/packages/b2c-dx-mcp/test/tools/cartridges/index.test.ts +++ b/packages/b2c-dx-mcp/test/tools/cartridges/index.test.ts @@ -53,11 +53,11 @@ function createMockB2CInstance(options?: {codeVersion?: string}): B2CInstance { /** * Create a mock services instance for testing. */ -function createMockServices(options?: {b2cInstance?: B2CInstance; workingDirectory?: string}): Services { +function createMockServices(options?: {b2cInstance?: B2CInstance; projectDirectory?: string}): Services { return new Services({ b2cInstance: options?.b2cInstance, resolvedConfig: createMockResolvedConfig({ - workingDirectory: options?.workingDirectory, + projectDirectory: options?.projectDirectory, }), }); } @@ -67,7 +67,7 @@ function createMockServices(options?: {b2cInstance?: B2CInstance; workingDirecto */ function createMockLoadServicesWrapper(options?: { b2cInstance?: B2CInstance; - workingDirectory?: string; + projectDirectory?: string; }): () => Services { const services = createMockServices(options); return () => services; @@ -136,7 +136,7 @@ describe('tools/cartridges', () => { describe('cartridge_deploy execution', () => { it('should call findAndDeployCartridges with instance and default directory', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const mockResult: DeployResult = { cartridges: [{name: 'app_storefront_base', src: '/path/to/app_storefront_base', dest: 'app_storefront_base'}], @@ -146,7 +146,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -162,7 +162,7 @@ describe('tools/cartridges', () => { DeployOptions, ]; expect(instance).to.equal(mockInstance); - expect(dir).to.equal(workingDir); + expect(dir).to.equal(projectDir); expect(options.include).to.be.undefined; expect(options.exclude).to.be.undefined; expect(options.reload).to.be.undefined; @@ -172,9 +172,9 @@ describe('tools/cartridges', () => { }); it('should call findAndDeployCartridges with custom directory', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const directory = './cartridges'; - const expectedResolvedPath = path.resolve(workingDir, directory); + const expectedResolvedPath = path.resolve(projectDir, directory); const mockResult: DeployResult = { cartridges: [{name: 'my_cartridge', src: '/path/to/my_cartridge', dest: 'my_cartridge'}], @@ -184,7 +184,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -277,9 +277,9 @@ describe('tools/cartridges', () => { }); it('should pass all options together', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const directory = './cartridges'; - const expectedResolvedPath = path.resolve(workingDir, directory); + const expectedResolvedPath = path.resolve(projectDir, directory); const cartridges = ['app_storefront_base']; const exclude = ['test_cartridge']; const reload = true; @@ -292,7 +292,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -342,13 +342,13 @@ describe('tools/cartridges', () => { expect(jsonResult.cartridges[1].name).to.equal('app_core'); }); - it('should resolve relative directory paths relative to working directory', async () => { - const workingDir = '/path/to/project'; + it('should resolve relative directory paths relative to project directory', async () => { + const projectDir = '/path/to/project'; const relativePaths = ['./cartridges', 'cartridges', '../cartridges', './src/cartridges']; for (const relativePath of relativePaths) { findAndDeployCartridgesStub.resetHistory(); - const expectedResolvedPath = path.resolve(workingDir, relativePath); + const expectedResolvedPath = path.resolve(projectDir, relativePath); const mockResult: DeployResult = { cartridges: [{name: 'test_cartridge', src: '/path/to/test', dest: 'test_cartridge'}], @@ -358,7 +358,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -374,7 +374,7 @@ describe('tools/cartridges', () => { }); it('should use absolute directory paths as-is', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const absolutePaths = process.platform === 'win32' ? [String.raw`C:\cartridges`, String.raw`D:\projects\cartridges`] @@ -391,7 +391,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -406,8 +406,8 @@ describe('tools/cartridges', () => { } }); - it('should use working directory when directory is not provided', async () => { - const workingDir = '/path/to/project'; + it('should use project directory when directory is not provided', async () => { + const projectDir = '/path/to/project'; const mockResult: DeployResult = { cartridges: [{name: 'test_cartridge', src: '/path/to/test', dest: 'test_cartridge'}], @@ -417,7 +417,7 @@ describe('tools/cartridges', () => { findAndDeployCartridgesStub.resolves(mockResult); const mockInstance = createMockB2CInstance(); - const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, workingDirectory: workingDir}); + const loadServices = createMockLoadServicesWrapper({b2cInstance: mockInstance, projectDirectory: projectDir}); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, getActiveCodeVersion: getActiveCodeVersionStub, @@ -427,10 +427,10 @@ describe('tools/cartridges', () => { expect(findAndDeployCartridgesStub.calledOnce).to.be.true; const [, dir] = findAndDeployCartridgesStub.firstCall.args as [B2CInstance, string, DeployOptions]; - expect(dir).to.equal(workingDir); + expect(dir).to.equal(projectDir); }); - it('should use process.cwd() when workingDirectory is not configured', async () => { + it('should use process.cwd() when projectDirectory is not configured', async () => { const directory = './cartridges'; const expectedResolvedPath = path.resolve(process.cwd(), directory); @@ -444,7 +444,7 @@ describe('tools/cartridges', () => { const mockInstance = createMockB2CInstance(); const loadServices = createMockLoadServicesWrapper({ b2cInstance: mockInstance, - // No workingDirectory provided - should fall back to process.cwd() + // No projectDirectory provided - should fall back to process.cwd() }); const tool = createCartridgesTools(loadServices, { findAndDeployCartridges: findAndDeployCartridgesStub, diff --git a/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts b/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts index 2f8d661e..66780887 100644 --- a/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts +++ b/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts @@ -66,7 +66,7 @@ function createMockServices(options?: { mrtProject?: string; mrtEnvironment?: string; mrtOrigin?: string; - workingDirectory?: string; + projectDirectory?: string; }): Services { return new Services({ mrtConfig: { @@ -76,7 +76,7 @@ function createMockServices(options?: { origin: options?.mrtOrigin, }, resolvedConfig: createMockResolvedConfig({ - workingDirectory: options?.workingDirectory, + projectDirectory: options?.projectDirectory, }), }); } @@ -89,7 +89,7 @@ function createMockLoadServicesWrapper(options?: { mrtProject?: string; mrtEnvironment?: string; mrtOrigin?: string; - workingDirectory?: string; + projectDirectory?: string; }): () => Services { const services = createMockServices(options); return () => services; @@ -152,9 +152,9 @@ describe('tools/mrt', () => { describe('mrt_bundle_push execution', () => { it('should call pushBundle with project from mrtConfig', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 123, @@ -167,7 +167,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -184,9 +184,9 @@ describe('tools/mrt', () => { }); it('should not pass environment as target when deploy is false (default)', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 456, @@ -200,7 +200,7 @@ describe('tools/mrt', () => { mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', mrtEnvironment: 'staging', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -217,9 +217,9 @@ describe('tools/mrt', () => { }); it('should not pass environment as target when deploy is explicitly false', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 789, @@ -233,7 +233,7 @@ describe('tools/mrt', () => { mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', mrtEnvironment: 'staging', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -250,9 +250,9 @@ describe('tools/mrt', () => { }); it('should call pushBundle with environment as target when deploy is true and environment is configured', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 456, @@ -267,7 +267,7 @@ describe('tools/mrt', () => { mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', mrtEnvironment: 'staging', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -285,9 +285,9 @@ describe('tools/mrt', () => { }); it('should call pushBundle with custom origin when configured', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const customOrigin = 'https://custom-cloud.mobify.com'; const mockResult: PushResult = { @@ -302,7 +302,7 @@ describe('tools/mrt', () => { mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', mrtOrigin: customOrigin, - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -319,9 +319,9 @@ describe('tools/mrt', () => { }); it('should pass message parameter to pushBundle', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 123, @@ -334,7 +334,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -347,9 +347,9 @@ describe('tools/mrt', () => { }); it('should return PushResult as JSON', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; - const expectedResolvedPath = path.resolve(workingDir, buildDir); + const expectedResolvedPath = path.resolve(projectDir, buildDir); const mockResult: PushResult = { bundleId: 12_345, @@ -362,7 +362,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -378,13 +378,13 @@ describe('tools/mrt', () => { expect(jsonResult.message).to.equal('Release v1.0.0'); }); - it('should resolve relative buildDirectory paths relative to working directory', async () => { - const workingDir = '/path/to/project'; + it('should resolve relative buildDirectory paths relative to project directory', async () => { + const projectDir = '/path/to/project'; const relativePaths = ['./build', 'build', '../build', './dist/build']; for (const relativePath of relativePaths) { pushBundleStub.resetHistory(); - const expectedResolvedPath = path.resolve(workingDir, relativePath); + const expectedResolvedPath = path.resolve(projectDir, relativePath); const mockResult: PushResult = { bundleId: 999, @@ -397,7 +397,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -411,7 +411,7 @@ describe('tools/mrt', () => { }); it('should use absolute buildDirectory paths as-is', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const absolutePaths = process.platform === 'win32' ? [String.raw`C:\build`, String.raw`D:\projects\build`] @@ -431,7 +431,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -445,8 +445,8 @@ describe('tools/mrt', () => { }); it('should use default build directory when buildDirectory is not provided', async () => { - const workingDir = '/path/to/project'; - const expectedDefaultPath = path.join(workingDir, 'build'); + const projectDir = '/path/to/project'; + const expectedDefaultPath = path.join(projectDir, 'build'); const mockResult: PushResult = { bundleId: 888, @@ -459,7 +459,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -470,7 +470,7 @@ describe('tools/mrt', () => { expect(options.buildDirectory).to.equal(expectedDefaultPath); }); - it('should use process.cwd() when workingDirectory is not configured', async () => { + it('should use process.cwd() when projectDirectory is not configured', async () => { const buildDir = './build'; const expectedResolvedPath = path.resolve(process.cwd(), buildDir); @@ -485,7 +485,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - // No workingDirectory provided - should fall back to process.cwd() + // No projectDirectory provided - should fall back to process.cwd() }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; @@ -551,7 +551,7 @@ describe('tools/mrt', () => { }); it('should return error when pushBundle throws', async () => { - const workingDir = '/path/to/project'; + const projectDir = '/path/to/project'; const buildDir = './build'; const error = new Error('Failed to push bundle: Network error'); @@ -560,7 +560,7 @@ describe('tools/mrt', () => { const loadServices = createMockLoadServicesWrapper({ mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project', - workingDirectory: workingDir, + projectDirectory: projectDir, }); const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; diff --git a/packages/b2c-dx-mcp/test/tools/storefrontnext/page-designer-decorator/index.test.ts b/packages/b2c-dx-mcp/test/tools/storefrontnext/page-designer-decorator/index.test.ts index 0e542551..49b4ea99 100644 --- a/packages/b2c-dx-mcp/test/tools/storefrontnext/page-designer-decorator/index.test.ts +++ b/packages/b2c-dx-mcp/test/tools/storefrontnext/page-designer-decorator/index.test.ts @@ -33,11 +33,11 @@ function getResultText(result: ToolResult): string { /** * Create a mock services instance for testing. * - * @param workingDirectory - Optional working directory (defaults to process.cwd()) + * @param projectDirectory - Optional project directory (defaults to process.cwd()) * @returns A new Services instance with empty configuration */ -function createMockServices(workingDirectory?: string): Services { - const config = createMockResolvedConfig({workingDirectory}); +function createMockServices(projectDirectory?: string): Services { + const config = createMockResolvedConfig({projectDirectory}); return new Services({resolvedConfig: config}); } @@ -124,7 +124,7 @@ describe('tools/storefrontnext/page-designer-decorator', () => { mkdirSync(testDir, {recursive: true}); originalCwd = process.cwd(); process.chdir(testDir); - // Create services with workingDirectory set to test directory + // Create services with projectDirectory set to test directory services = createMockServices(testDir); }); @@ -189,12 +189,12 @@ describe('tools/storefrontnext/page-designer-decorator', () => { expect(text).to.include('TestComponent'); }); - it('should use workingDirectory from Services', async () => { + it('should use projectDirectory from Services', async () => { const customDir = path.join(tmpdir(), `b2c-mcp-test-custom-${Date.now()}`); mkdirSync(customDir, {recursive: true}); createTestComponent(customDir, 'CustomComponent'); - // Create services with custom workingDirectory + // Create services with custom projectDirectory const customServices = createMockServices(customDir); const tool = createPageDesignerDecoratorTool(() => customServices); diff --git a/packages/b2c-plugin-example-config/src/sources/env-file-source.ts b/packages/b2c-plugin-example-config/src/sources/env-file-source.ts index 0c4980c7..30d9dd8d 100644 --- a/packages/b2c-plugin-example-config/src/sources/env-file-source.ts +++ b/packages/b2c-plugin-example-config/src/sources/env-file-source.ts @@ -58,10 +58,10 @@ export class EnvFileSource implements ConfigSource { * * File location priority: * 1. B2C_ENV_FILE_PATH environment variable (explicit override) - * 2. .env.b2c in workingDirectory (from options) + * 2. .env.b2c in projectDirectory (from options) * 3. .env.b2c in current working directory * - * @param options - Resolution options (workingDirectory used for file lookup) + * @param options - Resolution options (projectDirectory used for file lookup) * @returns Parsed configuration and location, or undefined if file not found */ load(options: ResolveConfigOptions): ConfigLoadResult | undefined { @@ -71,7 +71,7 @@ export class EnvFileSource implements ConfigSource { if (envOverride) { envFilePath = envOverride; } else { - const searchDir = options.workingDirectory ?? process.cwd(); + const searchDir = options.projectDirectory ?? process.cwd(); envFilePath = join(searchDir, '.env.b2c'); } diff --git a/packages/b2c-tooling-sdk/README.md b/packages/b2c-tooling-sdk/README.md index 39060aa4..be99e609 100644 --- a/packages/b2c-tooling-sdk/README.md +++ b/packages/b2c-tooling-sdk/README.md @@ -1,9 +1,9 @@ -# Salesforce Commerce Cloud B2C Tooling SDK +# Salesforce B2C Commerce Tooling SDK > [!NOTE] > This project is currently in **Developer Preview**. Not all features are implemented, and the API may change in future releases. -A TypeScript SDK for programmatic access to Salesforce Commerce Cloud B2C APIs including OCAPI, WebDAV, SLAS, ODS, and MRT. +A TypeScript SDK for programmatic access to Salesforce B2C Commerce APIs including OCAPI, WebDAV, SLAS, ODS, and MRT. [![Version](https://img.shields.io/npm/v/@salesforce/b2c-tooling-sdk.svg)](https://npmjs.org/package/@salesforce/b2c-tooling-sdk) diff --git a/packages/b2c-tooling-sdk/package.json b/packages/b2c-tooling-sdk/package.json index 478ab45d..fca83814 100644 --- a/packages/b2c-tooling-sdk/package.json +++ b/packages/b2c-tooling-sdk/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/b2c-tooling-sdk", + "description": "Core tooling library for Salesforce B2C Commerce CLI", "version": "0.5.2", - "description": "Core tooling library for Salesforce Commerce Cloud B2C CLI", "author": "Charles Lavery", "license": "Apache-2.0", "repository": "SalesforceCommerceCloud/b2c-developer-tooling", diff --git a/packages/b2c-tooling-sdk/src/cli/base-command.ts b/packages/b2c-tooling-sdk/src/cli/base-command.ts index b792cae9..4e14acee 100644 --- a/packages/b2c-tooling-sdk/src/cli/base-command.ts +++ b/packages/b2c-tooling-sdk/src/cli/base-command.ts @@ -303,7 +303,7 @@ export abstract class BaseCommand extends Command { * Gets base configuration options from common flags. * * Subclasses should spread these options when overriding loadConfiguration() - * to ensure common options like workingDirectory are always included. + * to ensure common options like projectDirectory are always included. * * @example * ```typescript @@ -320,6 +320,7 @@ export abstract class BaseCommand extends Command { return { instance: this.flags.instance, configPath: this.flags.config, + projectDirectory: this.flags['project-directory'], workingDirectory: this.flags['project-directory'], }; } diff --git a/packages/b2c-tooling-sdk/src/cli/config.ts b/packages/b2c-tooling-sdk/src/cli/config.ts index e09ab293..14b67d90 100644 --- a/packages/b2c-tooling-sdk/src/cli/config.ts +++ b/packages/b2c-tooling-sdk/src/cli/config.ts @@ -174,7 +174,9 @@ export interface LoadConfigOptions { instance?: string; /** Explicit path to config file (skips searching if provided) */ configPath?: string; - /** Starting directory for config file search (default: current working directory) */ + /** Starting directory for config file search (default: current project directory) */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; /** Cloud origin for MRT ~/.mobify lookup (e.g., https://cloud-staging.mobify.com) */ cloudOrigin?: string; @@ -236,16 +238,18 @@ export function loadConfig( ): ResolvedB2CConfig { const logger = getLogger(); - // Preserve instanceName and workingDirectory from options if not already in flags + // Preserve instanceName and projectDirectory from options if not already in flags const effectiveFlags = { ...flags, instanceName: flags.instanceName ?? options.instance, + projectDirectory: flags.projectDirectory ?? options.projectDirectory, workingDirectory: flags.workingDirectory ?? options.workingDirectory, }; const resolved = resolveConfig(effectiveFlags, { instance: options.instance, configPath: options.configPath, + projectDirectory: options.projectDirectory, workingDirectory: options.workingDirectory, hostnameProtection: true, cloudOrigin: options.cloudOrigin, diff --git a/packages/b2c-tooling-sdk/src/config/dw-json.ts b/packages/b2c-tooling-sdk/src/config/dw-json.ts index f043d4ea..41a6d80d 100644 --- a/packages/b2c-tooling-sdk/src/config/dw-json.ts +++ b/packages/b2c-tooling-sdk/src/config/dw-json.ts @@ -96,6 +96,8 @@ export interface LoadDwJsonOptions { /** Explicit path to dw.json (skips searching if provided) */ path?: string; /** Starting directory for search (defaults to cwd) */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; } @@ -112,7 +114,7 @@ export interface LoadDwJsonResult { /** * Finds dw.json by searching upward from the starting directory. * - * @param workingDirectory - Directory to start searching from (defaults to cwd) + * @param projectDirectory - Directory to start searching from (defaults to cwd) * @returns Path to dw.json if found, undefined otherwise * * @example @@ -121,8 +123,8 @@ export interface LoadDwJsonResult { * console.log(`Found dw.json at ${dwPath}`); * } */ -export function findDwJson(workingDirectory: string = process.cwd()): string | undefined { - let dir = workingDirectory; +export function findDwJson(projectDirectory: string = process.cwd()): string | undefined { + let dir = projectDirectory; const root = path.parse(dir).root; while (dir !== root) { @@ -209,7 +211,8 @@ function selectConfig(json: DwJsonMultiConfig, instanceName?: string): DwJsonCon */ export function loadFullDwJson(options: LoadDwJsonOptions = {}): {config: DwJsonMultiConfig; path: string} | undefined { const logger = getLogger(); - const dwJsonPath = options.path ?? path.join(options.workingDirectory || process.cwd(), 'dw.json'); + const dwJsonPath = + options.path ?? path.join(options.projectDirectory ?? options.workingDirectory ?? process.cwd(), 'dw.json'); logger.trace({path: dwJsonPath}, '[DwJsonSource] Checking for config file'); @@ -247,6 +250,8 @@ export interface AddInstanceOptions { /** Path to dw.json (defaults to ./dw.json) */ path?: string; /** Starting directory for search */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; /** Whether to set as active instance */ setActive?: boolean; @@ -263,7 +268,8 @@ export interface AddInstanceOptions { * @throws Error if instance with same name already exists */ export function addInstance(instance: DwJsonConfig, options: AddInstanceOptions = {}): void { - const dwJsonPath = options.path ?? path.join(options.workingDirectory || process.cwd(), 'dw.json'); + const dwJsonPath = + options.path ?? path.join(options.projectDirectory || options.workingDirectory || process.cwd(), 'dw.json'); let existing: DwJsonMultiConfig = {}; if (fs.existsSync(dwJsonPath)) { @@ -322,6 +328,8 @@ export interface RemoveInstanceOptions { /** Path to dw.json */ path?: string; /** Starting directory for search */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; } @@ -333,7 +341,8 @@ export interface RemoveInstanceOptions { * @throws Error if instance not found or dw.json doesn't exist */ export function removeInstance(name: string, options: RemoveInstanceOptions = {}): void { - const dwJsonPath = options.path ?? path.join(options.workingDirectory || process.cwd(), 'dw.json'); + const dwJsonPath = + options.path ?? path.join(options.projectDirectory || options.workingDirectory || process.cwd(), 'dw.json'); if (!fs.existsSync(dwJsonPath)) { throw new Error('No dw.json file found'); @@ -364,6 +373,8 @@ export interface SetActiveInstanceOptions { /** Path to dw.json */ path?: string; /** Starting directory for search */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; } @@ -375,7 +386,8 @@ export interface SetActiveInstanceOptions { * @throws Error if instance not found or dw.json doesn't exist */ export function setActiveInstance(name: string, options: SetActiveInstanceOptions = {}): void { - const dwJsonPath = options.path ?? path.join(options.workingDirectory || process.cwd(), 'dw.json'); + const dwJsonPath = + options.path ?? path.join(options.projectDirectory || options.workingDirectory || process.cwd(), 'dw.json'); if (!fs.existsSync(dwJsonPath)) { throw new Error('No dw.json file found'); @@ -418,7 +430,7 @@ export function setActiveInstance(name: string, options: SetActiveInstanceOption * Loads configuration from a dw.json file. * * If an explicit path is provided, uses that file. Otherwise, looks for dw.json - * in the workingDirectory (or cwd). Does NOT search parent directories. + * in the projectDirectory (or cwd). Does NOT search parent directories. * * Use `findDwJson()` if you need to search upward through parent directories. * @@ -434,7 +446,7 @@ export function setActiveInstance(name: string, options: SetActiveInstanceOption * } * * // Load from specific directory - * const result = loadDwJson({ workingDirectory: '/path/to/project' }); + * const result = loadDwJson({ projectDirectory: '/path/to/project' }); * * // Use named instance * const result = loadDwJson({ instance: 'staging' }); @@ -446,7 +458,8 @@ export function loadDwJson(options: LoadDwJsonOptions = {}): LoadDwJsonResult | const logger = getLogger(); // If explicit path provided, use it. Otherwise default to ./dw.json (no upward search) - const dwJsonPath = options.path ?? path.join(options.workingDirectory || process.cwd(), 'dw.json'); + const dwJsonPath = + options.path ?? path.join(options.projectDirectory || options.workingDirectory || process.cwd(), 'dw.json'); logger.trace({path: dwJsonPath}, '[DwJsonSource] Checking for config file'); diff --git a/packages/b2c-tooling-sdk/src/config/mapping.ts b/packages/b2c-tooling-sdk/src/config/mapping.ts index 6315a596..377c2dcb 100644 --- a/packages/b2c-tooling-sdk/src/config/mapping.ts +++ b/packages/b2c-tooling-sdk/src/config/mapping.ts @@ -316,6 +316,7 @@ export function mergeConfigsWithProtection( cipHost: overrides.cipHost ?? base.cipHost, sandboxApiHost: overrides.sandboxApiHost ?? base.sandboxApiHost, instanceName: overrides.instanceName ?? base.instanceName, + projectDirectory: overrides.projectDirectory ?? base.projectDirectory, workingDirectory: overrides.workingDirectory ?? base.workingDirectory, mrtProject: overrides.mrtProject ?? base.mrtProject, mrtEnvironment: overrides.mrtEnvironment ?? base.mrtEnvironment, diff --git a/packages/b2c-tooling-sdk/src/config/sources/dw-json-source.ts b/packages/b2c-tooling-sdk/src/config/sources/dw-json-source.ts index 5350bc2d..1f6263fa 100644 --- a/packages/b2c-tooling-sdk/src/config/sources/dw-json-source.ts +++ b/packages/b2c-tooling-sdk/src/config/sources/dw-json-source.ts @@ -34,7 +34,7 @@ export class DwJsonSource implements ConfigSource { const result = loadDwJson({ instance: options.instance, path: options.configPath, - workingDirectory: options.workingDirectory, + projectDirectory: options.projectDirectory ?? options.workingDirectory, }); if (!result) { @@ -55,7 +55,7 @@ export class DwJsonSource implements ConfigSource { listInstances(options?: ResolveConfigOptions): InstanceInfo[] { const result = loadFullDwJson({ path: options?.configPath, - workingDirectory: options?.workingDirectory, + projectDirectory: options?.projectDirectory ?? options?.workingDirectory, }); if (!result) { @@ -101,7 +101,7 @@ export class DwJsonSource implements ConfigSource { const dwJsonConfig = mapNormalizedConfigToDwJson(options.config, options.name); addInstance(dwJsonConfig, { path: options.configPath, - workingDirectory: options.workingDirectory, + projectDirectory: options.projectDirectory ?? options.workingDirectory, setActive: options.setActive, }); } @@ -112,7 +112,7 @@ export class DwJsonSource implements ConfigSource { removeInstance(name: string, options?: ResolveConfigOptions): void { removeInstance(name, { path: options?.configPath, - workingDirectory: options?.workingDirectory, + projectDirectory: options?.projectDirectory ?? options?.workingDirectory, }); } @@ -122,7 +122,7 @@ export class DwJsonSource implements ConfigSource { setActiveInstance(name: string, options?: ResolveConfigOptions): void { setActiveInstance(name, { path: options?.configPath, - workingDirectory: options?.workingDirectory, + projectDirectory: options?.projectDirectory ?? options?.workingDirectory, }); } } diff --git a/packages/b2c-tooling-sdk/src/config/sources/package-json-source.ts b/packages/b2c-tooling-sdk/src/config/sources/package-json-source.ts index 49f9ed00..1790d769 100644 --- a/packages/b2c-tooling-sdk/src/config/sources/package-json-source.ts +++ b/packages/b2c-tooling-sdk/src/config/sources/package-json-source.ts @@ -60,8 +60,8 @@ export class PackageJsonSource implements ConfigSource { load(options: ResolveConfigOptions): ConfigLoadResult | undefined { const logger = getLogger(); - // Only look in cwd (or workingDirectory if provided) - const searchDir = options.workingDirectory ?? process.cwd(); + // Only look in cwd (or projectDirectory if provided) + const searchDir = options.projectDirectory ?? options.workingDirectory ?? process.cwd(); const packageJsonPath = path.join(searchDir, 'package.json'); logger.trace({location: packageJsonPath}, '[PackageJsonSource] Checking for package.json'); diff --git a/packages/b2c-tooling-sdk/src/config/types.ts b/packages/b2c-tooling-sdk/src/config/types.ts index bd779a4d..d3c92687 100644 --- a/packages/b2c-tooling-sdk/src/config/types.ts +++ b/packages/b2c-tooling-sdk/src/config/types.ts @@ -80,6 +80,8 @@ export interface NormalizedConfig { /** Instance name (from multi-config supporting sources) */ instanceName?: string; /** Starting directory for config file search and project-relative operations */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; // TLS/mTLS @@ -143,6 +145,8 @@ export interface ResolveConfigOptions { /** Explicit path to config file (defaults to auto-discover) */ configPath?: string; /** Starting directory for config file search */ + projectDirectory?: string; + /** @deprecated Use projectDirectory instead */ workingDirectory?: string; /** Whether to apply hostname mismatch protection (default: true) */ hostnameProtection?: boolean; diff --git a/packages/b2c-tooling-sdk/src/operations/logs/path-normalizer.ts b/packages/b2c-tooling-sdk/src/operations/logs/path-normalizer.ts index 9ce50c68..84bf5e8b 100644 --- a/packages/b2c-tooling-sdk/src/operations/logs/path-normalizer.ts +++ b/packages/b2c-tooling-sdk/src/operations/logs/path-normalizer.ts @@ -181,7 +181,7 @@ export function createPathNormalizer(options: PathNormalizerOptions): ((message: * * This is a convenience function that combines `findCartridges` with * `createPathNormalizer` for easy setup. Cartridge paths are converted - * to relative paths from the current working directory. + * to relative paths from the current project directory. * * @param directory - Directory to search for cartridges (defaults to cwd) * @returns Path normalizer function, or undefined if no cartridges found diff --git a/packages/b2c-tooling-sdk/test/config/sources.test.ts b/packages/b2c-tooling-sdk/test/config/sources.test.ts index 34dbb849..cce9d5b5 100644 --- a/packages/b2c-tooling-sdk/test/config/sources.test.ts +++ b/packages/b2c-tooling-sdk/test/config/sources.test.ts @@ -552,7 +552,7 @@ describe('config/sources', () => { // Use PackageJsonSource directly to test in isolation const source = new PackageJsonSource(); - const result = source.load({workingDirectory: tempDir}); + const result = source.load({projectDirectory: tempDir}); expect(result).to.not.be.undefined; expect(result!.config.shortCode).to.equal('abc123'); @@ -683,7 +683,7 @@ describe('config/sources', () => { ); const source = new PackageJsonSource(); - const result = source.load({workingDirectory: tempDir}); + const result = source.load({projectDirectory: tempDir}); expect(result).to.not.be.undefined; expect(result!.config.shortCode).to.equal('abc123'); @@ -709,7 +709,7 @@ describe('config/sources', () => { ); const source = new PackageJsonSource(); - const result = source.load({workingDirectory: tempDir}); + const result = source.load({projectDirectory: tempDir}); expect(result).to.not.be.undefined; expect(result!.config.shortCode).to.equal('abc123'); diff --git a/packages/b2c-vs-extension/README.md b/packages/b2c-vs-extension/README.md index 584f61a7..884e4840 100644 --- a/packages/b2c-vs-extension/README.md +++ b/packages/b2c-vs-extension/README.md @@ -1,6 +1,6 @@ # B2C DX - VS Code Extension -VS Code extension for B2C Commerce Cloud developer experience: Page Designer assistant, B2C CLI integration, and Cursor agent prompts. +VS Code extension for B2C Commerce developer experience: Page Designer assistant, B2C CLI integration, and Cursor agent prompts. **Full documentation:** [IDE Support](https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/ide-support.html) in the B2C Developer Tooling docs (VitePress). diff --git a/packages/b2c-vs-extension/package.json b/packages/b2c-vs-extension/package.json index fe0851e9..9f748ed9 100644 --- a/packages/b2c-vs-extension/package.json +++ b/packages/b2c-vs-extension/package.json @@ -1,7 +1,7 @@ { "name": "b2c-vs-extension", "displayName": "B2C DX VSCE", - "description": "VS Code extension for B2C Commerce Cloud developer experience (Page Designer assistant, B2C CLI integration)", + "description": "VS Code extension for B2C Commerce developer experience (Page Designer assistant, B2C CLI integration)", "version": "0.0.6", "publisher": "Salesforce", "license": "Apache-2.0", diff --git a/skills/README.md b/skills/README.md index d19fbc66..5097dd2c 100644 --- a/skills/README.md +++ b/skills/README.md @@ -8,7 +8,7 @@ These skills follow the [Agent Skills](https://agentskills.io/home) format and c | Plugin | Description | |--------|-------------| -| `b2c-cli` | Skills for Salesforce Commerce Cloud B2C CLI operations | +| `b2c-cli` | Skills for Salesforce B2C Commerce CLI operations | | `b2c` | B2C Commerce development skills including Custom API development guides | ## Installation