@salesforce/b2c-dx-mcp 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +15 -62
  2. package/dist/commands/mcp.d.ts +1 -0
  3. package/dist/commands/mcp.js +47 -9
  4. package/dist/registry.d.ts +3 -4
  5. package/dist/registry.js +7 -14
  6. package/dist/services.d.ts +21 -1
  7. package/dist/services.js +38 -1
  8. package/dist/tools/adapter.d.ts +19 -2
  9. package/dist/tools/adapter.js +49 -10
  10. package/dist/tools/cartridges/index.js +11 -3
  11. package/dist/tools/diagnostics/config-inspect.js +2 -2
  12. package/dist/tools/diagnostics/debug-list-sessions.js +1 -0
  13. package/dist/tools/diagnostics/debug-start-session.js +13 -2
  14. package/dist/tools/diagnostics/log-watch-registry.d.ts +3 -0
  15. package/dist/tools/diagnostics/log-watch-registry.js +1 -0
  16. package/dist/tools/diagnostics/logs-watch-list.js +1 -0
  17. package/dist/tools/diagnostics/logs-watch-start.js +6 -1
  18. package/dist/tools/diagnostics/mrt-log-watch-registry.d.ts +3 -0
  19. package/dist/tools/diagnostics/mrt-log-watch-registry.js +0 -0
  20. package/dist/tools/diagnostics/mrt-logs-watch-list.js +1 -0
  21. package/dist/tools/diagnostics/mrt-logs-watch-start.js +7 -1
  22. package/dist/tools/diagnostics/session-registry.d.ts +3 -0
  23. package/dist/tools/diagnostics/session-registry.js +2 -1
  24. package/dist/tools/index.d.ts +0 -1
  25. package/dist/tools/index.js +0 -1
  26. package/dist/tools/mrt/index.js +4 -0
  27. package/dist/tools/project-context.d.ts +42 -11
  28. package/dist/tools/project-context.js +48 -15
  29. package/dist/tools/scapi/metrics-get.js +1 -1
  30. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +4 -0
  31. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +27 -7
  32. package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -1
  33. package/dist/tools/scapi/scapi-schemas-list.js +1 -0
  34. package/dist/utils/constants.d.ts +2 -13
  35. package/dist/utils/constants.js +1 -20
  36. package/oclif.manifest.json +2 -2
  37. package/package.json +3 -3
  38. package/content/sfnext/auth.md +0 -62
  39. package/content/sfnext/components.md +0 -123
  40. package/content/sfnext/config.md +0 -180
  41. package/content/sfnext/data-fetching.md +0 -323
  42. package/content/sfnext/extensions.md +0 -80
  43. package/content/sfnext/i18n.md +0 -121
  44. package/content/sfnext/page-designer.md +0 -78
  45. package/content/sfnext/performance.md +0 -80
  46. package/content/sfnext/pitfalls.md +0 -141
  47. package/content/sfnext/quick-reference.md +0 -226
  48. package/content/sfnext/state-management.md +0 -75
  49. package/content/sfnext/styling.md +0 -51
  50. package/content/sfnext/testing.md +0 -232
  51. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +0 -24
  52. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +0 -53
  53. package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +0 -45
  54. package/dist/tools/storefrontnext/figma/figma-to-component/index.js +0 -332
  55. package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +0 -40
  56. package/dist/tools/storefrontnext/figma/generate-component/decision.js +0 -312
  57. package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +0 -9
  58. package/dist/tools/storefrontnext/figma/generate-component/formatter.js +0 -92
  59. package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +0 -117
  60. package/dist/tools/storefrontnext/figma/generate-component/index.js +0 -102
  61. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +0 -71
  62. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +0 -260
  63. package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +0 -64
  64. package/dist/tools/storefrontnext/figma/map-tokens/index.js +0 -242
  65. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +0 -65
  66. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +0 -268
  67. package/dist/tools/storefrontnext/index.d.ts +0 -30
  68. package/dist/tools/storefrontnext/index.js +0 -28
  69. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.d.ts +0 -169
  70. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +0 -567
  71. package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +0 -259
  72. package/dist/tools/storefrontnext/page-designer-decorator/index.js +0 -622
  73. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.d.ts +0 -8
  74. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.js +0 -65
  75. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.d.ts +0 -13
  76. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.js +0 -87
  77. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.d.ts +0 -4
  78. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.js +0 -55
  79. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.d.ts +0 -22
  80. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.js +0 -109
  81. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.d.ts +0 -21
  82. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.js +0 -60
  83. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.d.ts +0 -27
  84. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.js +0 -68
  85. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.d.ts +0 -4
  86. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.js +0 -65
  87. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.d.ts +0 -11
  88. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.js +0 -92
  89. package/dist/tools/storefrontnext/page-designer-decorator/rules.d.ts +0 -51
  90. package/dist/tools/storefrontnext/page-designer-decorator/rules.js +0 -70
  91. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.d.ts +0 -116
  92. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.js +0 -350
  93. package/dist/tools/storefrontnext/sfnext-development-guidelines.d.ts +0 -9
  94. package/dist/tools/storefrontnext/sfnext-development-guidelines.js +0 -141
  95. package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +0 -92
  96. package/dist/tools/storefrontnext/site-theming/color-contrast.js +0 -186
  97. package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +0 -16
  98. package/dist/tools/storefrontnext/site-theming/color-mapping.js +0 -131
  99. package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +0 -11
  100. package/dist/tools/storefrontnext/site-theming/guidance-merger.js +0 -78
  101. package/dist/tools/storefrontnext/site-theming/index.d.ts +0 -14
  102. package/dist/tools/storefrontnext/site-theming/index.js +0 -128
  103. package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +0 -16
  104. package/dist/tools/storefrontnext/site-theming/response-builder.js +0 -316
  105. package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +0 -64
  106. package/dist/tools/storefrontnext/site-theming/theming-store.js +0 -417
  107. package/dist/tools/storefrontnext/site-theming/types.d.ts +0 -36
  108. package/dist/tools/storefrontnext/site-theming/types.js +0 -7
package/README.md CHANGED
@@ -61,30 +61,27 @@ See the [Installation Guide](https://salesforcecommercecloud.github.io/b2c-devel
61
61
 
62
62
  **Project-level configuration** (recommended for Cursor and GitHub Copilot) automatically detects your project location. For **user-level configuration** or when using explicit paths, set `--project-directory` (or `SFCC_PROJECT_DIRECTORY`). MCP clients spawn from the home directory (`~`), not your project.
63
63
 
64
- | Environment Variable | Description |
65
- |---------------------|-------------|
64
+ | Environment Variable | Description |
65
+ | ------------------------ | ------------------------------------------------------------- |
66
66
  | `SFCC_PROJECT_DIRECTORY` | Project directory (enables auto-discovery and config loading) |
67
- | `SFCC_SERVER` | B2C instance hostname |
68
- | `SFCC_USERNAME` | Username for WebDAV |
69
- | `SFCC_PASSWORD` | Password/access key for WebDAV |
70
- | `SFCC_CLIENT_ID` | OAuth client ID |
71
- | `SFCC_CLIENT_SECRET` | OAuth client secret |
72
- | `MRT_API_KEY` | MRT API key (`SFCC_MRT_API_KEY` also supported) |
67
+ | `SFCC_SERVER` | B2C instance hostname |
68
+ | `SFCC_USERNAME` | Username for WebDAV |
69
+ | `SFCC_PASSWORD` | Password/access key for WebDAV |
70
+ | `SFCC_CLIENT_ID` | OAuth client ID |
71
+ | `SFCC_CLIENT_SECRET` | OAuth client secret |
72
+ | `MRT_API_KEY` | MRT API key (`SFCC_MRT_API_KEY` also supported) |
73
73
 
74
74
  See the [Configuration Guide](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/configuration) for credentials, flags, and toolset selection.
75
75
 
76
76
  ## Tools
77
77
 
78
- | Toolset | Tools | Docs |
79
- |---------|-------|------|
80
- | CARTRIDGES | `cartridge_deploy` | [toolsets#cartridges](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#cartridges) |
81
- | MRT | `mrt_bundle_push` | [toolsets#mrt](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#mrt) |
82
- | SCAPI | `scapi_schemas_list`, `scapi_custom_apis_get_status`, `scapi_custom_api_generate_scaffold` | [toolsets#scapi](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#scapi) |
83
- | STOREFRONTNEXT | `mrt_bundle_push` + SCAPI tools (auto-enabled for Storefront Next projects) | [toolsets#storefrontnext](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#storefrontnext) |
84
- | STOREFRONTNEXT_DEPRECATED ⛔ | `sfnext_get_guidelines`, `sfnext_add_page_designer_decorator`, `sfnext_configure_theme`, `sfnext_start_figma_workflow`, `sfnext_analyze_component`, `sfnext_match_tokens_to_theme` — **deprecated, see note below** | [toolsets#storefrontnext-deprecated](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#storefrontnext-deprecated) |
85
- | PWAV3 | `pwakit_get_guidelines` + SCAPI tools | [toolsets#pwav3](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#pwav3) |
86
-
87
- > **⛔ `sfnext_*` tools are deprecated.** The Storefront Next MCP tools are **not compatible with the Storefront Next 1.0 GA release** and have been superseded by the [`storefront-next` and `storefront-next-figma` agent-skills plugins](https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/agent-skills), which stay current with the GA release. They have moved to the `STOREFRONTNEXT_DEPRECATED` toolset, which is **never auto-enabled** and **excluded from `--toolsets all`**; to use them you must request the toolset explicitly (`--toolsets STOREFRONTNEXT_DEPRECATED --allow-non-ga-tools`). They will be removed in a future release.
78
+ | Toolset | Tools | Docs |
79
+ | -------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
80
+ | CARTRIDGES | `cartridge_deploy` | [toolsets#cartridges](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#cartridges) |
81
+ | MRT | `mrt_bundle_push` | [toolsets#mrt](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#mrt) |
82
+ | SCAPI | `scapi_schemas_list`, `scapi_custom_apis_get_status`, `scapi_custom_api_generate_scaffold` | [toolsets#scapi](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#scapi) |
83
+ | STOREFRONTNEXT | `mrt_bundle_push` + SCAPI tools (auto-enabled for Storefront Next projects) | [toolsets#storefrontnext](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#storefrontnext) |
84
+ | PWAV3 | `pwakit_get_guidelines` + SCAPI tools | [toolsets#pwav3](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/toolsets#pwav3) |
88
85
 
89
86
  ### cartridge_deploy
90
87
 
@@ -121,49 +118,6 @@ Generate new custom SCAPI endpoint in a cartridge. [Details](https://salesforcec
121
118
  - "Use the MCP tool to scaffold a new custom API named my-products."
122
119
  - "Use the MCP tool to create a custom admin API called customer-trips."
123
120
 
124
- ## Deprecated: Storefront Next (`sfnext_*`) tools
125
-
126
- > **⛔ Deprecated and not compatible with the Storefront Next 1.0 GA release.** The tools below have been superseded by the [`storefront-next` and `storefront-next-figma` agent-skills plugins](https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/agent-skills) and will be removed in a future release. They no longer auto-enable for Storefront Next projects and are excluded from `--toolsets all`; to use them, request `--toolsets STOREFRONTNEXT_DEPRECATED --allow-non-ga-tools`. Migrate to the skills plugins.
127
-
128
- ### sfnext_get_guidelines
129
-
130
- Get Storefront Next guidelines and best practices. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-get-guidelines)
131
-
132
- - "Use the MCP tool to show me critical Storefront Next rules."
133
- - "Use the MCP tool to get data-fetching and component patterns."
134
-
135
- ### sfnext_add_page_designer_decorator
136
-
137
- Add Page Designer decorators to components. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-add-page-designer-decorator)
138
-
139
- - "Use the MCP tool to add Page Designer decorators to my component."
140
-
141
- ### sfnext_configure_theme
142
-
143
- Get theming guidelines, questions, and WCAG color validation for Storefront Next. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-configure-theme)
144
-
145
- - "Use the MCP tool to help me apply my brand colors to my Storefront Next site."
146
- - "Use the MCP tool to validate my color combinations for accessibility."
147
-
148
- ### sfnext_start_figma_workflow
149
-
150
- Workflow orchestrator for Figma-to-component conversion. Parses Figma URL, returns step-by-step instructions for subsequent tool calls. Requires external Figma MCP server. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-start-figma-workflow) — [Figma Setup](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/figma-tools-setup)
151
-
152
- - "Use the MCP tool to convert this Figma design to a Storefront Next component: [Figma URL with node-id]"
153
- - "Use the MCP tool to create this homepage from the Figma design: [Figma URL with node-id]"
154
-
155
- ### sfnext_analyze_component
156
-
157
- Analyze design and discovered components to recommend REUSE, EXTEND, or CREATE strategy. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-analyze-component)
158
-
159
- - "Use the MCP tool to analyze the Figma design and recommend whether to reuse, extend, or create a component."
160
-
161
- ### sfnext_match_tokens_to_theme
162
-
163
- Map design tokens to existing theme tokens in app.css with confidence scores and suggestions. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/sfnext-match-tokens-to-theme)
164
-
165
- - "Use the MCP tool to map these Figma design tokens to my theme."
166
-
167
121
  ### pwakit_get_guidelines
168
122
 
169
123
  Get PWA Kit v3 guidelines. [Details](https://salesforcecommercecloud.github.io/b2c-developer-tooling/mcp/tools/pwakit-get-guidelines)
@@ -187,4 +141,3 @@ For MCP development, testing, and local setup, see [CONTRIBUTING.md](./CONTRIBUT
187
141
  ## License
188
142
 
189
143
  This project is licensed under the Apache License 2.0. See [LICENSE.txt](../../LICENSE.txt) for full details.
190
-
@@ -87,6 +87,7 @@ export default class McpServerCommand extends BaseCommand<typeof McpServerComman
87
87
  * 2. Startup --config / SFCC_CONFIG
88
88
  * 3. SFCC_CONFIG from the selected project's .env
89
89
  * 4. dw.json in the selected project directory
90
+ * 5. Shared default dw.json from the tooling settings
90
91
  *
91
92
  * Values are then merged through the normal CLI resolver, including
92
93
  * environment, plugin, dw.json, ~/.mobify, and package.json sources.
@@ -247,14 +247,15 @@ export default class McpServerCommand extends BaseCommand {
247
247
  * 2. Startup --config / SFCC_CONFIG
248
248
  * 3. SFCC_CONFIG from the selected project's .env
249
249
  * 4. dw.json in the selected project directory
250
+ * 5. Shared default dw.json from the tooling settings
250
251
  *
251
252
  * Values are then merged through the normal CLI resolver, including
252
253
  * environment, plugin, dw.json, ~/.mobify, and package.json sources.
253
254
  */
254
255
  async loadConfiguration(projectContext) {
255
256
  const mrt = extractMrtFlags(this.flags);
256
- const baseOptions = this.getBaseConfigOptions();
257
- const effectiveProjectDirectory = projectContext?.projectDirectory ?? baseOptions.projectDirectory;
257
+ const baseOptions = this.flags ? this.getBaseConfigOptions() : {};
258
+ const effectiveProjectDirectory = path.resolve(projectContext?.projectDirectory ?? baseOptions.projectDirectory ?? process.cwd());
258
259
  const projectEnvironment = this.loadProjectEnvironment(effectiveProjectDirectory);
259
260
  const projectConfigPath = projectEnvironment?.SFCC_CONFIG;
260
261
  const configPath = (projectContext?.configPath
@@ -270,10 +271,9 @@ export default class McpServerCommand extends BaseCommand {
270
271
  ...baseOptions,
271
272
  ...mrt.options,
272
273
  configPath,
273
- ...(projectContext?.projectDirectory && {
274
- projectDirectory: projectContext.projectDirectory,
275
- workingDirectory: projectContext.projectDirectory,
276
- }),
274
+ instance: projectContext?.instanceName ?? baseOptions.instance,
275
+ projectDirectory: effectiveProjectDirectory,
276
+ workingDirectory: effectiveProjectDirectory,
277
277
  };
278
278
  // Combine B2C instance flags and MRT config flags
279
279
  const flagConfig = {
@@ -295,9 +295,39 @@ export default class McpServerCommand extends BaseCommand {
295
295
  */
296
296
  async loadServices(projectContext) {
297
297
  const config = await this.loadConfiguration(projectContext);
298
- const effectiveProjectDirectory = projectContext?.projectDirectory ?? this.flags?.['project-directory'];
298
+ const baseOptions = this.flags ? this.getBaseConfigOptions() : {};
299
+ const configuredProjectDirectory = baseOptions.projectDirectory;
300
+ const effectiveProjectDirectory = path.resolve(projectContext?.projectDirectory ?? configuredProjectDirectory ?? process.cwd());
299
301
  const projectEnvironment = this.loadProjectEnvironment(effectiveProjectDirectory);
300
- return Services.fromResolvedConfig(config, projectEnvironment);
302
+ const projectConfigPath = projectEnvironment?.SFCC_CONFIG;
303
+ let primaryConfiguration;
304
+ if (projectContext?.configPath) {
305
+ primaryConfiguration = {
306
+ path: path.resolve(effectiveProjectDirectory, projectContext.configPath),
307
+ source: 'argument',
308
+ };
309
+ }
310
+ else if (baseOptions.configPath) {
311
+ primaryConfiguration = { path: path.resolve(baseOptions.configPath), source: 'server' };
312
+ }
313
+ else if (projectConfigPath) {
314
+ primaryConfiguration = {
315
+ path: path.isAbsolute(projectConfigPath)
316
+ ? projectConfigPath
317
+ : path.resolve(effectiveProjectDirectory, projectConfigPath),
318
+ source: 'projectEnvironment',
319
+ };
320
+ }
321
+ else {
322
+ primaryConfiguration = { path: path.join(effectiveProjectDirectory, 'dw.json'), source: 'projectDirectory' };
323
+ }
324
+ return Services.fromResolvedConfig(config, projectEnvironment, {
325
+ projectDirectory: {
326
+ path: effectiveProjectDirectory,
327
+ source: projectContext?.projectDirectory ? 'argument' : configuredProjectDirectory ? 'config' : 'cwd',
328
+ },
329
+ primaryConfiguration,
330
+ });
301
331
  }
302
332
  /**
303
333
  * Main entry point - starts the MCP server.
@@ -360,7 +390,15 @@ export default class McpServerCommand extends BaseCommand {
360
390
  this.serverContext = new ServerContext();
361
391
  // Register toolsets with loader function that loads config and creates Services on each tool call
362
392
  // This allows tools to pick up changes to config files (dw.json, ~/.mobify) between invocations
363
- await registerToolsets(startupFlags, server, this.loadServices.bind(this), this.serverContext);
393
+ const loadServices = this.loadServices.bind(this);
394
+ const configuredProjectDirectory = this.flags['project-directory'];
395
+ loadServices.projectContextDefaults = {
396
+ projectDirectory: {
397
+ path: path.resolve(configuredProjectDirectory ?? process.cwd()),
398
+ source: configuredProjectDirectory ? 'config' : 'cwd',
399
+ },
400
+ };
401
+ await registerToolsets(startupFlags, server, loadServices, this.serverContext);
364
402
  // Connect to stdio transport
365
403
  const transport = new StdioServerTransport();
366
404
  await server.connect(transport);
@@ -2,9 +2,8 @@ import { type ProjectType } from '@salesforce/b2c-tooling-sdk/discovery';
2
2
  import { type DocCategory } from '@salesforce/b2c-tooling-sdk/docs';
3
3
  import type { McpTool, Toolset, StartupFlags } from './utils/index.js';
4
4
  import type { B2CDxMcpServer } from './server.js';
5
- import type { Services } from './services.js';
6
5
  import type { ServerContext } from './server-context.js';
7
- import type { ProjectContextInput } from './tools/project-context.js';
6
+ import type { ServicesLoader } from './tools/adapter.js';
8
7
  /**
9
8
  * Registry of tools organized by toolset.
10
9
  * Tools can belong to multiple toolsets via their `toolsets` array.
@@ -18,5 +17,5 @@ export type ToolRegistry = Record<Toolset, McpTool[]>;
18
17
  * @param loadServices - Function that loads configuration and returns Services instance
19
18
  * @returns Complete tool registry
20
19
  */
21
- export declare function createToolRegistry(loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext, detectedWorkspaces?: readonly ProjectType[], enabledDocCategories?: readonly DocCategory[]): ToolRegistry;
22
- export declare function registerToolsets(flags: StartupFlags, server: B2CDxMcpServer, loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext): Promise<void>;
20
+ export declare function createToolRegistry(loadServices: ServicesLoader, serverContext?: ServerContext, detectedWorkspaces?: readonly ProjectType[], enabledDocCategories?: readonly DocCategory[]): ToolRegistry;
21
+ export declare function registerToolsets(flags: StartupFlags, server: B2CDxMcpServer, loadServices: ServicesLoader, serverContext?: ServerContext): Promise<void>;
package/dist/registry.js CHANGED
@@ -5,17 +5,17 @@
5
5
  */
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
8
9
  import { getLogger } from '@salesforce/b2c-tooling-sdk/logging';
9
10
  import { detectWorkspaceType } from '@salesforce/b2c-tooling-sdk/discovery';
10
11
  import { DOC_CATEGORIES, resolveEnabledCategories } from '@salesforce/b2c-tooling-sdk/docs';
11
- import { ALL_TOOLSETS, DEPRECATED_TOOLSETS, TOOLSETS, VALID_TOOLSET_NAMES } from './utils/index.js';
12
+ import { ALL_TOOLSETS, TOOLSETS, VALID_TOOLSET_NAMES } from './utils/index.js';
12
13
  import { createCartridgesTools } from './tools/cartridges/index.js';
13
14
  import { createDiagnosticsTools } from './tools/diagnostics/index.js';
14
15
  import { createDocsTools } from './tools/docs/index.js';
15
16
  import { createMrtTools } from './tools/mrt/index.js';
16
17
  import { createPwav3Tools } from './tools/pwav3/index.js';
17
18
  import { createScapiTools } from './tools/scapi/index.js';
18
- import { createStorefrontNextTools } from './tools/storefrontnext/index.js';
19
19
  /**
20
20
  * Base toolsets that are always enabled regardless of detected project type.
21
21
  * - SCAPI: SCAPI discovery and custom API scaffolding tools.
@@ -33,9 +33,6 @@ const PROJECT_TYPE_TOOLSETS = {
33
33
  // (A SFRA workspace also matches the `cartridges` marker; the union dedupes.)
34
34
  sfra: ['CARTRIDGES'],
35
35
  'pwa-kit-v3': ['PWAV3', 'MRT'],
36
- // Note: STOREFRONTNEXT_DEPRECATED is intentionally NOT auto-activated. The
37
- // legacy sfnext_* tools are superseded by the storefront-next agent-skills
38
- // plugins and must be explicitly requested via --toolsets.
39
36
  'storefront-next': ['STOREFRONTNEXT', 'MRT', 'CARTRIDGES'],
40
37
  };
41
38
  /**
@@ -84,7 +81,6 @@ export function createToolRegistry(loadServices, serverContext, detectedWorkspac
84
81
  PWAV3: [],
85
82
  SCAPI: [],
86
83
  STOREFRONTNEXT: [],
87
- STOREFRONTNEXT_DEPRECATED: [],
88
84
  };
89
85
  // Collect all tools from all factories
90
86
  const allTools = [
@@ -94,7 +90,6 @@ export function createToolRegistry(loadServices, serverContext, detectedWorkspac
94
90
  ...createMrtTools(loadServices),
95
91
  ...createPwav3Tools(loadServices),
96
92
  ...createScapiTools(loadServices),
97
- ...createStorefrontNextTools(loadServices),
98
93
  ];
99
94
  // Organize tools by their declared toolsets (supports multi-toolset)
100
95
  for (const tool of allTools) {
@@ -117,6 +112,7 @@ export function createToolRegistry(loadServices, serverContext, detectedWorkspac
117
112
  * without descending into unrelated deep trees.
118
113
  */
119
114
  const DISCOVERY_MAX_DEPTH = 5;
115
+ const MCP_PACKAGE_DIRECTORY = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
120
116
  /**
121
117
  * Returns true when `dir` is a location that should never be recursively
122
118
  * scanned for a workspace: the user's home directory or a filesystem root.
@@ -130,7 +126,7 @@ function isUnscannableRoot(dir) {
130
126
  return true;
131
127
  }
132
128
  const home = os.homedir();
133
- return Boolean(home) && path.resolve(home) === resolved;
129
+ return (Boolean(home) && path.resolve(home) === resolved) || resolved === MCP_PACKAGE_DIRECTORY;
134
130
  }
135
131
  /**
136
132
  * Performs workspace auto-discovery and returns appropriate toolsets.
@@ -157,7 +153,7 @@ async function detectProjectTypes(flags) {
157
153
  // Never recursively scan a home directory or filesystem root — the scan would
158
154
  // be expensive and would not identify a meaningful workspace anyway.
159
155
  if (isUnscannableRoot(projectDirectory)) {
160
- logger.warn({ projectDirectory }, 'Project directory is a home or root directory; skipping workspace auto-discovery. ' +
156
+ logger.warn({ projectDirectory }, 'Project directory is a home, filesystem root, or MCP installation directory; skipping workspace auto-discovery. ' +
161
157
  'Set --project-directory or SFCC_PROJECT_DIRECTORY to the project path to enable it.');
162
158
  return [];
163
159
  }
@@ -224,12 +220,9 @@ export async function registerToolsets(flags, server, loadServices, serverContex
224
220
  if (invalidToolsets.length > 0) {
225
221
  logger.warn({ invalidToolsets, validToolsets: VALID_TOOLSET_NAMES }, `Ignoring invalid toolset(s): "${invalidToolsets.join('", "')}"`);
226
222
  }
227
- // Determine which toolsets to enable.
228
- // `ALL` expands to every toolset EXCEPT deprecated ones — deprecated toolsets
229
- // must always be named explicitly.
223
+ // Determine which toolsets to enable. `ALL` expands to every toolset.
230
224
  const validToolsets = toolsets.filter((t) => TOOLSETS.includes(t));
231
- const allNonDeprecatedToolsets = TOOLSETS.filter((t) => !DEPRECATED_TOOLSETS.includes(t));
232
- const toolsetsToEnable = new Set(toolsets.includes(ALL_TOOLSETS) ? allNonDeprecatedToolsets : validToolsets);
225
+ const toolsetsToEnable = new Set(toolsets.includes(ALL_TOOLSETS) ? TOOLSETS : validToolsets);
233
226
  // Auto-discovery: only when no valid toolsets AND no valid individual tools
234
227
  // were provided. This handles both (1) no flags provided, and (2) all
235
228
  // provided flags are invalid. Skip workspace detection entirely otherwise —
@@ -40,6 +40,7 @@ import fs from 'node:fs';
40
40
  import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
41
41
  import type { AuthStrategy } from '@salesforce/b2c-tooling-sdk/auth';
42
42
  import type { ResolvedB2CConfig } from '@salesforce/b2c-tooling-sdk/config';
43
+ import type { ConfigurationResolutionSource, ProjectDirectoryInfo, ToolResolution } from './tools/project-context.js';
43
44
  import { WebDavClient, type CustomApisClient, type MetricsClient, type ScapiSchemasClient } from '@salesforce/b2c-tooling-sdk/clients';
44
45
  /**
45
46
  * MRT (Managed Runtime) configuration.
@@ -67,6 +68,18 @@ export interface ServicesOptions {
67
68
  resolvedConfig: ResolvedB2CConfig;
68
69
  /** Project-scoped environment parsed from the effective project's .env file. */
69
70
  projectEnvironment?: Readonly<Record<string, string | undefined>>;
71
+ /** Inputs needed to attribute project and primary-configuration selection. */
72
+ resolution?: ServicesResolutionInputs;
73
+ }
74
+ /** Resolution inputs captured centrally by the MCP command for one tool call. */
75
+ export interface ServicesResolutionInputs {
76
+ /** Effective project directory and its selection source. */
77
+ projectDirectory: ProjectDirectoryInfo;
78
+ /** Primary configuration candidate selected before the SDK resolver runs. */
79
+ primaryConfiguration?: {
80
+ path: string;
81
+ source: Exclude<ConfigurationResolutionSource, 'globalDefault' | 'none'>;
82
+ };
70
83
  }
71
84
  /**
72
85
  * Services class that provides utilities for MCP tools.
@@ -103,6 +116,7 @@ export declare class Services {
103
116
  * @private
104
117
  */
105
118
  private readonly projectEnvironment;
119
+ private readonly resolution;
106
120
  private readonly resolvedConfig;
107
121
  constructor(opts: ServicesOptions);
108
122
  /**
@@ -117,7 +131,7 @@ export declare class Services {
117
131
  * const services = Services.fromResolvedConfig(this.resolvedConfig);
118
132
  * ```
119
133
  */
120
- static fromResolvedConfig(config: ResolvedB2CConfig, projectEnvironment?: Readonly<Record<string, string | undefined>>): Services;
134
+ static fromResolvedConfig(config: ResolvedB2CConfig, projectEnvironment?: Readonly<Record<string, string | undefined>>, resolution?: ServicesResolutionInputs): Services;
121
135
  /**
122
136
  * Check if a file or directory exists.
123
137
  *
@@ -175,6 +189,12 @@ export declare class Services {
175
189
  * Get OS platform information.
176
190
  */
177
191
  getPlatform(): NodeJS.Platform;
192
+ /**
193
+ * Get compact project and selected-configuration provenance for MCP results.
194
+ * Detailed source graphs remain available through {@link getResolvedConfig}
195
+ * for the config_inspect tool.
196
+ */
197
+ getResolution(): ToolResolution;
178
198
  /**
179
199
  * Get the resolved configuration (values, sources, warnings).
180
200
  *
package/dist/services.js CHANGED
@@ -45,6 +45,28 @@ import fs from 'node:fs';
45
45
  import path from 'node:path';
46
46
  import os from 'node:os';
47
47
  import { createCustomApisClient, createMetricsClient, createScapiSchemasClient, toOrganizationId, WebDavClient, } from '@salesforce/b2c-tooling-sdk/clients';
48
+ function createToolResolution(config, inputs) {
49
+ const configuredProjectDirectory = config.values.projectDirectory;
50
+ const projectDirectory = inputs?.projectDirectory ??
51
+ (configuredProjectDirectory
52
+ ? { path: configuredProjectDirectory, source: 'config' }
53
+ : { path: process.cwd(), source: 'cwd' });
54
+ const dwJsonSource = config.sources.find((source) => source.name === 'DwJsonSource' && source.location);
55
+ const configurationSource = dwJsonSource
56
+ ? dwJsonSource.scope === 'global'
57
+ ? 'globalDefault'
58
+ : (inputs?.primaryConfiguration?.source ?? 'projectDirectory')
59
+ : 'none';
60
+ return {
61
+ projectDirectory,
62
+ configuration: {
63
+ ...(dwJsonSource?.location ? { path: dwJsonSource.location } : {}),
64
+ source: configurationSource,
65
+ ...(config.values.instanceName ? { instanceName: config.values.instanceName } : {}),
66
+ ...(config.values.hostname ? { hostname: config.values.hostname } : {}),
67
+ },
68
+ };
69
+ }
48
70
  /**
49
71
  * Services class that provides utilities for MCP tools.
50
72
  *
@@ -80,12 +102,14 @@ export class Services {
80
102
  * @private
81
103
  */
82
104
  projectEnvironment;
105
+ resolution;
83
106
  resolvedConfig;
84
107
  constructor(opts) {
85
108
  this.b2cInstance = opts.b2cInstance;
86
109
  this.mrtConfig = opts.mrtConfig ?? {};
87
110
  this.resolvedConfig = opts.resolvedConfig;
88
111
  this.projectEnvironment = opts.projectEnvironment ?? {};
112
+ this.resolution = createToolResolution(opts.resolvedConfig, opts.resolution);
89
113
  }
90
114
  /**
91
115
  * Creates a Services instance from an already-resolved configuration.
@@ -99,7 +123,7 @@ export class Services {
99
123
  * const services = Services.fromResolvedConfig(this.resolvedConfig);
100
124
  * ```
101
125
  */
102
- static fromResolvedConfig(config, projectEnvironment) {
126
+ static fromResolvedConfig(config, projectEnvironment, resolution) {
103
127
  // Build MRT config using factory methods
104
128
  const mrtConfig = {
105
129
  auth: config.hasMrtConfig() ? config.createMrtAuth() : undefined,
@@ -114,6 +138,7 @@ export class Services {
114
138
  mrtConfig,
115
139
  resolvedConfig: config,
116
140
  projectEnvironment,
141
+ resolution,
117
142
  });
118
143
  }
119
144
  // ============================================
@@ -216,6 +241,18 @@ export class Services {
216
241
  getPlatform() {
217
242
  return os.platform();
218
243
  }
244
+ /**
245
+ * Get compact project and selected-configuration provenance for MCP results.
246
+ * Detailed source graphs remain available through {@link getResolvedConfig}
247
+ * for the config_inspect tool.
248
+ */
249
+ getResolution() {
250
+ return {
251
+ projectDirectory: { ...this.resolution.projectDirectory },
252
+ ...(this.resolution.configuration ? { configuration: { ...this.resolution.configuration } } : {}),
253
+ ...(this.resolution.directories ? { directories: { ...this.resolution.directories } } : {}),
254
+ };
255
+ }
219
256
  /**
220
257
  * Get the resolved configuration (values, sources, warnings).
221
258
  *
@@ -69,7 +69,12 @@ import type { B2CInstance } from '@salesforce/b2c-tooling-sdk';
69
69
  import type { McpTool, ToolResult, Toolset } from '../utils/index.js';
70
70
  import type { Services, MrtConfig } from '../services.js';
71
71
  import type { ServerContext } from '../server-context.js';
72
- import { type ProjectContextInput } from './project-context.js';
72
+ import { type DirectoryResolutionInfo, type ProjectContextDefaults, type ProjectContextInput, type ToolResolution } from './project-context.js';
73
+ /** Services loader enriched with registration-time project fallback provenance. */
74
+ export interface ServicesLoader {
75
+ (projectContext?: ProjectContextInput): Promise<Services> | Services;
76
+ projectContextDefaults?: ProjectContextDefaults;
77
+ }
73
78
  /**
74
79
  * Context provided to tool execute functions.
75
80
  * Contains the B2CInstance and/or MRT config based on tool requirements.
@@ -96,6 +101,10 @@ export interface ToolExecutionContext {
96
101
  * Created once at server startup and shared across all tool invocations.
97
102
  */
98
103
  serverContext?: ServerContext;
104
+ /** Compact resolution provenance that will be attached to this tool result. */
105
+ resolution: ToolResolution;
106
+ /** Record a specialized directory resolved by the tool. */
107
+ setResolvedDirectory: (name: string, value: DirectoryResolutionInfo) => void;
99
108
  }
100
109
  /**
101
110
  * Options for creating a tool adapter.
@@ -132,6 +141,12 @@ export interface ToolAdapterOptions<TInput, TOutput> {
132
141
  * input and use it while loading Services.
133
142
  */
134
143
  usesProjectContext?: boolean;
144
+ /**
145
+ * Whether this tool selects project configuration without requiring a
146
+ * B2CInstance or MRT auth object (for example config_inspect or SCAPI clients).
147
+ * Adds projectDirectory, configPath, and instanceName to the public schema.
148
+ */
149
+ usesConfigurationContext?: boolean;
135
150
  /**
136
151
  * Execute function that performs the tool's operation.
137
152
  * Receives validated input and a context with B2CInstance and/or auth based on requirements.
@@ -180,6 +195,8 @@ export declare function errorResult(message: string): ToolResult;
180
195
  * ```
181
196
  */
182
197
  export declare function jsonResult(data: unknown, indent?: number): ToolResult;
198
+ /** Attach compact resolution provenance while preserving existing tool output. */
199
+ export declare function attachResolution(result: ToolResult, resolution: ToolResolution): ToolResult;
183
200
  /**
184
201
  * Creates an MCP tool from a b2c-tooling function.
185
202
  *
@@ -219,4 +236,4 @@ export declare function jsonResult(data: unknown, indent?: number): ToolResult;
219
236
  * }, loadServices);
220
237
  * ```
221
238
  */
222
- export declare function createToolAdapter<TInput, TOutput>(options: ToolAdapterOptions<TInput, TOutput>, loadServices: (projectContext?: ProjectContextInput) => Promise<Services> | Services, serverContext?: ServerContext): McpTool;
239
+ export declare function createToolAdapter<TInput, TOutput>(options: ToolAdapterOptions<TInput, TOutput>, loadServices: ServicesLoader, serverContext?: ServerContext): McpTool;
@@ -70,7 +70,7 @@
70
70
  * ```
71
71
  */
72
72
  import { z } from 'zod';
73
- import { projectContextInputSchema } from './project-context.js';
73
+ import { createProjectContextInputSchema, } from './project-context.js';
74
74
  /**
75
75
  * Creates a text-only success result.
76
76
  *
@@ -121,6 +121,25 @@ export function jsonResult(data, indent = 2) {
121
121
  content: [{ type: 'text', text: JSON.stringify(data, null, indent) }],
122
122
  };
123
123
  }
124
+ /** Attach compact resolution provenance while preserving existing tool output. */
125
+ export function attachResolution(result, resolution) {
126
+ let content = result.content;
127
+ let structuredContent = { ...result.structuredContent, resolution };
128
+ if (content.length === 1 && content[0]?.type === 'text') {
129
+ try {
130
+ const parsed = JSON.parse(content[0].text);
131
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
132
+ const output = { ...parsed, resolution };
133
+ content = [{ ...content[0], text: JSON.stringify(output, null, 2) }];
134
+ structuredContent = { ...output, ...result.structuredContent, resolution };
135
+ }
136
+ }
137
+ catch {
138
+ // Plain-text tools expose resolution through structuredContent only.
139
+ }
140
+ }
141
+ return { ...result, content, structuredContent };
142
+ }
124
143
  /**
125
144
  * Formats Zod validation errors into a human-readable string.
126
145
  *
@@ -170,10 +189,17 @@ function formatZodErrors(error) {
170
189
  * ```
171
190
  */
172
191
  export function createToolAdapter(options, loadServices, serverContext) {
173
- const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, usesProjectContext = false, execute, formatOutput, } = options;
174
- const effectiveUsesProjectContext = usesProjectContext || requiresInstance || requiresMrtAuth;
175
- const effectiveInputSchema = effectiveUsesProjectContext
176
- ? { ...projectContextInputSchema, ...inputSchema }
192
+ const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, usesProjectContext = false, usesConfigurationContext = false, execute, formatOutput, } = options;
193
+ const projectContextKind = requiresInstance || requiresMrtAuth || usesConfigurationContext
194
+ ? 'configuration'
195
+ : usesProjectContext
196
+ ? 'project'
197
+ : undefined;
198
+ const effectiveInputSchema = projectContextKind
199
+ ? {
200
+ ...createProjectContextInputSchema(projectContextKind, loadServices.projectContextDefaults),
201
+ ...inputSchema,
202
+ }
177
203
  : inputSchema;
178
204
  // Create Zod schema from inputSchema definition
179
205
  const zodSchema = z.object(effectiveInputSchema);
@@ -190,15 +216,21 @@ export function createToolAdapter(options, loadServices, serverContext) {
190
216
  return errorResult(`Invalid input: ${formatZodErrors(parseResult.error)}`);
191
217
  }
192
218
  const args = parseResult.data;
219
+ let resolution;
193
220
  try {
194
221
  // 2. Load Services to get fresh configuration (re-reads config files)
195
- const projectContext = effectiveUsesProjectContext ? args : undefined;
222
+ const projectContext = projectContextKind ? args : undefined;
196
223
  const services = await loadServices(projectContext);
224
+ const executionResolution = services.getResolution();
225
+ if (projectContextKind === 'project') {
226
+ delete executionResolution.configuration;
227
+ }
228
+ resolution = projectContextKind ? executionResolution : undefined;
197
229
  // 3. Get B2CInstance if required (loaded on each call)
198
230
  let b2cInstance;
199
231
  if (requiresInstance) {
200
232
  if (!services.b2cInstance) {
201
- return errorResult('B2C instance error: Instance configuration required. Provide --server flag, set SFCC_SERVER environment variable, or configure dw.json');
233
+ return attachResolution(errorResult('B2C instance error: Instance configuration required. Provide --server flag, set SFCC_SERVER environment variable, or configure dw.json'), executionResolution);
202
234
  }
203
235
  b2cInstance = services.b2cInstance;
204
236
  }
@@ -206,7 +238,7 @@ export function createToolAdapter(options, loadServices, serverContext) {
206
238
  let mrtConfig;
207
239
  if (requiresMrtAuth) {
208
240
  if (!services.mrtConfig.auth) {
209
- return errorResult('MRT auth error: MRT API key required. Provide --api-key, set MRT_API_KEY environment variable, or configure ~/.mobify');
241
+ return attachResolution(errorResult('MRT auth error: MRT API key required. Provide --api-key, set MRT_API_KEY environment variable, or configure ~/.mobify'), executionResolution);
210
242
  }
211
243
  mrtConfig = {
212
244
  auth: services.mrtConfig.auth,
@@ -221,15 +253,22 @@ export function createToolAdapter(options, loadServices, serverContext) {
221
253
  mrtConfig,
222
254
  services,
223
255
  serverContext,
256
+ resolution: executionResolution,
257
+ setResolvedDirectory(name, value) {
258
+ executionResolution.directories ??= {};
259
+ executionResolution.directories[name] = value;
260
+ },
224
261
  };
225
262
  const output = await execute(args, context);
226
263
  // 6. Format output
227
- return formatOutput(output);
264
+ const result = formatOutput(output);
265
+ return resolution ? attachResolution(result, executionResolution) : result;
228
266
  }
229
267
  catch (error) {
230
268
  // Handle execution errors
231
269
  const message = error instanceof Error ? error.message : String(error);
232
- return errorResult(`Execution error: ${message}`);
270
+ const result = errorResult(`Execution error: ${message}`);
271
+ return resolution ? attachResolution(result, resolution) : result;
233
272
  }
234
273
  },
235
274
  };
@@ -46,11 +46,14 @@ function createCartridgeDeployTool(loadServices, injections) {
46
46
  requiresInstance: true,
47
47
  usesProjectContext: true,
48
48
  inputSchema: {
49
+ cartridgeDirectory: z
50
+ .string()
51
+ .optional()
52
+ .describe('Optional cartridge discovery root. Relative paths resolve from projectDirectory. Defaults to projectDirectory.'),
49
53
  directory: z
50
54
  .string()
51
55
  .optional()
52
- .describe('Path to directory to search for cartridges. Defaults to current project directory if not specified. ' +
53
- 'The tool will recursively search this directory for .project files to identify cartridges.'),
56
+ .describe('Deprecated alias for cartridgeDirectory. cartridgeDirectory takes precedence when both are supplied.'),
54
57
  cartridges: z
55
58
  .array(z.string())
56
59
  .optional()
@@ -89,7 +92,12 @@ function createCartridgeDeployTool(loadServices, injections) {
89
92
  }
90
93
  // Resolve directory path: relative paths are resolved relative to project directory, absolute paths are used as-is
91
94
  const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
92
- const directory = context.services.resolveWithProjectDirectory(args.directory, args.projectDirectory);
95
+ const directoryArgument = args.cartridgeDirectory ?? args.directory;
96
+ const directory = context.services.resolveWithProjectDirectory(directoryArgument, args.projectDirectory);
97
+ context.setResolvedDirectory('cartridgeDirectory', {
98
+ path: directory,
99
+ source: directoryArgument ? 'argument' : 'projectDirectory',
100
+ });
93
101
  // Parse options
94
102
  const options = {
95
103
  include: args.cartridges,