@salesforce/b2c-dx-mcp 0.4.3 → 0.4.5

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 (80) hide show
  1. package/README.md +82 -370
  2. package/content/pwav3/components.md +400 -0
  3. package/content/pwav3/config.md +124 -0
  4. package/content/pwav3/data-fetching.md +213 -0
  5. package/content/pwav3/extensibility.md +167 -0
  6. package/content/pwav3/i18n.md +214 -0
  7. package/content/pwav3/quick-reference.md +169 -0
  8. package/content/pwav3/routing.md +107 -0
  9. package/content/pwav3/state-management.md +193 -0
  10. package/content/pwav3/styling.md +248 -0
  11. package/content/pwav3/testing.md +124 -0
  12. package/content/site-theming/theming-accessibility.md +126 -0
  13. package/content/site-theming/theming-questions.md +208 -0
  14. package/content/site-theming/theming-validation.md +174 -0
  15. package/dist/registry.js +1 -1
  16. package/dist/services.d.ts +10 -10
  17. package/dist/services.js +19 -12
  18. package/dist/tools/cartridges/index.js +1 -6
  19. package/dist/tools/index.d.ts +1 -4
  20. package/dist/tools/index.js +1 -4
  21. package/dist/tools/mrt/index.js +1 -6
  22. package/dist/tools/pwav3/index.d.ts +12 -3
  23. package/dist/tools/pwav3/index.js +5 -63
  24. package/dist/tools/pwav3/pwa-kit-development-guidelines.d.ts +9 -0
  25. package/dist/tools/pwav3/pwa-kit-development-guidelines.js +151 -0
  26. package/dist/tools/scapi/index.d.ts +1 -1
  27. package/dist/tools/scapi/index.js +6 -1
  28. package/dist/tools/scapi/scapi-custom-api-scaffold.d.ts +60 -0
  29. package/dist/tools/scapi/scapi-custom-api-scaffold.js +175 -0
  30. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +24 -0
  31. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +53 -0
  32. package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +42 -0
  33. package/dist/tools/storefrontnext/figma/figma-to-component/index.js +325 -0
  34. package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +40 -0
  35. package/dist/tools/storefrontnext/figma/generate-component/decision.js +312 -0
  36. package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +9 -0
  37. package/dist/tools/storefrontnext/figma/generate-component/formatter.js +92 -0
  38. package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +114 -0
  39. package/dist/tools/storefrontnext/figma/generate-component/index.js +98 -0
  40. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +71 -0
  41. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +260 -0
  42. package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +61 -0
  43. package/dist/tools/storefrontnext/figma/map-tokens/index.js +234 -0
  44. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +65 -0
  45. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +268 -0
  46. package/dist/tools/storefrontnext/index.d.ts +17 -0
  47. package/dist/tools/storefrontnext/index.js +10 -60
  48. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +15 -0
  49. package/dist/tools/storefrontnext/page-designer-decorator/index.js +3 -3
  50. package/dist/tools/storefrontnext/{developer-guidelines.js → sfnext-development-guidelines.js} +3 -3
  51. package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +92 -0
  52. package/dist/tools/storefrontnext/site-theming/color-contrast.js +186 -0
  53. package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +16 -0
  54. package/dist/tools/storefrontnext/site-theming/color-mapping.js +131 -0
  55. package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +11 -0
  56. package/dist/tools/storefrontnext/site-theming/guidance-merger.js +78 -0
  57. package/dist/tools/storefrontnext/site-theming/index.d.ts +14 -0
  58. package/dist/tools/storefrontnext/site-theming/index.js +122 -0
  59. package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +16 -0
  60. package/dist/tools/storefrontnext/site-theming/response-builder.js +316 -0
  61. package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +62 -0
  62. package/dist/tools/storefrontnext/site-theming/theming-store.js +410 -0
  63. package/dist/tools/storefrontnext/site-theming/types.d.ts +35 -0
  64. package/dist/tools/storefrontnext/site-theming/types.js +7 -0
  65. package/oclif.manifest.json +1 -1
  66. package/package.json +9 -6
  67. /package/content/{auth.md → sfnext/auth.md} +0 -0
  68. /package/content/{components.md → sfnext/components.md} +0 -0
  69. /package/content/{config.md → sfnext/config.md} +0 -0
  70. /package/content/{data-fetching.md → sfnext/data-fetching.md} +0 -0
  71. /package/content/{extensions.md → sfnext/extensions.md} +0 -0
  72. /package/content/{i18n.md → sfnext/i18n.md} +0 -0
  73. /package/content/{page-designer.md → sfnext/page-designer.md} +0 -0
  74. /package/content/{performance.md → sfnext/performance.md} +0 -0
  75. /package/content/{pitfalls.md → sfnext/pitfalls.md} +0 -0
  76. /package/content/{quick-reference.md → sfnext/quick-reference.md} +0 -0
  77. /package/content/{state-management.md → sfnext/state-management.md} +0 -0
  78. /package/content/{styling.md → sfnext/styling.md} +0 -0
  79. /package/content/{testing.md → sfnext/testing.md} +0 -0
  80. /package/dist/tools/storefrontnext/{developer-guidelines.d.ts → sfnext-development-guidelines.d.ts} +0 -0
package/dist/services.js CHANGED
@@ -233,18 +233,6 @@ export class Services {
233
233
  }
234
234
  return this.b2cInstance.webdav;
235
235
  }
236
- /**
237
- * Get the project project directory.
238
- * Falls back to process.cwd() if not explicitly set.
239
- *
240
- * This is the directory where the project is located, which may differ from process.cwd()
241
- * when MCP clients spawn servers from a different location (e.g., home directory).
242
- *
243
- * @returns Project project directory path
244
- */
245
- getWorkingDirectory() {
246
- return this.resolvedConfig.values.projectDirectory ?? process.cwd();
247
- }
248
236
  /**
249
237
  * Join path segments.
250
238
  *
@@ -285,6 +273,25 @@ export class Services {
285
273
  resolvePath(...segments) {
286
274
  return path.resolve(...segments);
287
275
  }
276
+ /**
277
+ * Resolve a path relative to the project directory.
278
+ * If path is not supplied, returns the project directory.
279
+ * If path is absolute, returns it as-is.
280
+ * If path is relative, resolves it relative to the project directory.
281
+ *
282
+ * @param pathArg - Optional path to resolve
283
+ * @returns Resolved absolute path
284
+ */
285
+ resolveWithProjectDirectory(pathArg) {
286
+ const projectDir = this.resolvedConfig.values.projectDirectory ?? process.cwd();
287
+ if (!pathArg) {
288
+ return projectDir;
289
+ }
290
+ if (path.isAbsolute(pathArg)) {
291
+ return pathArg;
292
+ }
293
+ return path.resolve(projectDir, pathArg);
294
+ }
288
295
  /**
289
296
  * Get file or directory stats.
290
297
  *
@@ -10,7 +10,6 @@
10
10
  *
11
11
  * @module tools/cartridges
12
12
  */
13
- import path from 'node:path';
14
13
  import { z } from 'zod';
15
14
  import { createToolAdapter, jsonResult } from '../adapter.js';
16
15
  import { findAndDeployCartridges, getActiveCodeVersion } from '@salesforce/b2c-tooling-sdk/operations/code';
@@ -84,11 +83,7 @@ function createCartridgeDeployTool(loadServices, injections) {
84
83
  instance.config.codeVersion = codeVersion;
85
84
  }
86
85
  // Resolve directory path: relative paths are resolved relative to project directory, absolute paths are used as-is
87
- const directory = args.directory
88
- ? path.isAbsolute(args.directory)
89
- ? args.directory
90
- : path.resolve(context.services.getWorkingDirectory(), args.directory)
91
- : context.services.getWorkingDirectory();
86
+ const directory = context.services.resolveWithProjectDirectory(args.directory);
92
87
  // Parse options
93
88
  const options = {
94
89
  include: args.cartridges,
@@ -3,10 +3,7 @@
3
3
  *
4
4
  * This module exports all available tools and utilities.
5
5
  * Tools use the @salesforce/b2c-tooling-sdk operations layer directly.
6
- *
7
- * > ⚠️ **PLACEHOLDER - ACTIVE DEVELOPMENT**
8
- * > Tools are currently placeholder implementations that return mock responses.
9
- * > Actual implementations are coming soon. Use `--allow-non-ga-tools` flag to enable.
6
+ * Use `--allow-non-ga-tools` flag to enable tools (preview release).
10
7
  *
11
8
  * @module tools
12
9
  */
@@ -8,10 +8,7 @@
8
8
  *
9
9
  * This module exports all available tools and utilities.
10
10
  * Tools use the @salesforce/b2c-tooling-sdk operations layer directly.
11
- *
12
- * > ⚠️ **PLACEHOLDER - ACTIVE DEVELOPMENT**
13
- * > Tools are currently placeholder implementations that return mock responses.
14
- * > Actual implementations are coming soon. Use `--allow-non-ga-tools` flag to enable.
11
+ * Use `--allow-non-ga-tools` flag to enable tools (preview release).
15
12
  *
16
13
  * @module tools
17
14
  */
@@ -10,7 +10,6 @@
10
10
  *
11
11
  * @module tools/mrt
12
12
  */
13
- import path from 'node:path';
14
13
  import { z } from 'zod';
15
14
  import { createToolAdapter, jsonResult } from '../adapter.js';
16
15
  import { pushBundle } from '@salesforce/b2c-tooling-sdk/operations/mrt';
@@ -75,11 +74,7 @@ function createMrtBundlePushTool(loadServices, injections) {
75
74
  // Parse comma-separated glob patterns (same as CLI defaults)
76
75
  const ssrOnly = (args.ssrOnly || 'ssr.js,ssr.mjs,server/**/*').split(',').map((s) => s.trim());
77
76
  const ssrShared = (args.ssrShared || 'static/**/*,client/**/*').split(',').map((s) => s.trim());
78
- const buildDirectory = args.buildDirectory
79
- ? path.isAbsolute(args.buildDirectory)
80
- ? args.buildDirectory
81
- : path.resolve(context.services.getWorkingDirectory(), args.buildDirectory)
82
- : path.join(context.services.getWorkingDirectory(), 'build');
77
+ const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory || 'build');
83
78
  // Log all computed variables before pushing bundle
84
79
  const logger = getLogger();
85
80
  logger.debug({
@@ -1,11 +1,20 @@
1
+ /**
2
+ * PWA Kit v3 toolset for B2C Commerce.
3
+ *
4
+ * This toolset provides MCP tools for PWA Kit v3 development.
5
+ * PWA Kit-specific tools are planned for future releases.
6
+ * mrt_bundle_push (from MRT toolset) is available for PWAV3 projects.
7
+ *
8
+ * @module tools/pwav3
9
+ */
1
10
  import type { McpTool } from '../../utils/index.js';
2
11
  import type { Services } from '../../services.js';
3
12
  /**
4
13
  * Creates all tools for the PWAV3 toolset.
5
14
  *
6
- * Note: mrt_bundle_push is defined in the MRT toolset with
7
- * toolsets: ["MRT", "PWAV3", "STOREFRONTNEXT"] and will
8
- * automatically appear in PWAV3.
15
+ * PWA Kit-specific tools are not yet implemented. mrt_bundle_push is defined
16
+ * in the MRT toolset with toolsets: ["MRT", "PWAV3", "STOREFRONTNEXT"] and
17
+ * automatically appears in PWAV3 for bundle deployment.
9
18
  *
10
19
  * @param loadServices - Function that loads configuration and returns Services instance
11
20
  * @returns Array of MCP tools
@@ -3,76 +3,18 @@
3
3
  * SPDX-License-Identifier: Apache-2
4
4
  * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
5
  */
6
- /**
7
- * PWA Kit v3 toolset for B2C Commerce.
8
- *
9
- * This toolset provides MCP tools for PWA Kit v3 development.
10
- *
11
- * > ⚠️ **PLACEHOLDER - ACTIVE DEVELOPMENT**
12
- * > Tools in this module are placeholder implementations that return mock responses.
13
- * > Actual implementations are coming soon. Use `--allow-non-ga-tools` flag to enable.
14
- *
15
- * @module tools/pwav3
16
- */
17
- import { z } from 'zod';
18
- import { createToolAdapter, jsonResult } from '../adapter.js';
19
- /**
20
- * Creates a placeholder tool for PWA Kit development.
21
- *
22
- * Placeholder tools log invocations and return mock responses until
23
- * the actual implementation is available.
24
- *
25
- * @param name - Tool name
26
- * @param description - Tool description
27
- * @param toolsets - Toolsets this tool belongs to
28
- * @param loadServices - Function that loads configuration and returns Services instance
29
- * @returns The configured MCP tool
30
- */
31
- function createPlaceholderTool(name, description, toolsets, loadServices) {
32
- return createToolAdapter({
33
- name,
34
- description: `[PLACEHOLDER] ${description}`,
35
- toolsets,
36
- isGA: false,
37
- requiresInstance: false,
38
- inputSchema: {
39
- message: z.string().optional().describe('Optional message to echo'),
40
- },
41
- async execute(args) {
42
- // Placeholder implementation
43
- const timestamp = new Date().toISOString();
44
- return {
45
- tool: name,
46
- status: 'placeholder',
47
- message: `This is a placeholder implementation for '${name}'. The actual implementation is coming soon.`,
48
- input: args,
49
- timestamp,
50
- };
51
- },
52
- formatOutput: (output) => jsonResult(output),
53
- }, loadServices);
54
- }
6
+ import { createDeveloperGuidelinesTool } from './pwa-kit-development-guidelines.js';
55
7
  /**
56
8
  * Creates all tools for the PWAV3 toolset.
57
9
  *
58
- * Note: mrt_bundle_push is defined in the MRT toolset with
59
- * toolsets: ["MRT", "PWAV3", "STOREFRONTNEXT"] and will
60
- * automatically appear in PWAV3.
10
+ * PWA Kit-specific tools are not yet implemented. mrt_bundle_push is defined
11
+ * in the MRT toolset with toolsets: ["MRT", "PWAV3", "STOREFRONTNEXT"] and
12
+ * automatically appears in PWAV3 for bundle deployment.
61
13
  *
62
14
  * @param loadServices - Function that loads configuration and returns Services instance
63
15
  * @returns Array of MCP tools
64
16
  */
65
17
  export function createPwav3Tools(loadServices) {
66
- return [
67
- // PWA Kit development tools
68
- createPlaceholderTool('pwakit_create_storefront', 'Create a new PWA Kit storefront project', ['PWAV3'], loadServices),
69
- createPlaceholderTool('pwakit_create_page', 'Create a new page component in PWA Kit project', ['PWAV3'], loadServices),
70
- createPlaceholderTool('pwakit_create_component', 'Create a new React component in PWA Kit project', ['PWAV3'], loadServices),
71
- createPlaceholderTool('pwakit_get_dev_guidelines', 'Get PWA Kit development guidelines and best practices', ['PWAV3'], loadServices),
72
- createPlaceholderTool('pwakit_recommend_hooks', 'Recommend appropriate React hooks for PWA Kit use cases', ['PWAV3'], loadServices),
73
- createPlaceholderTool('pwakit_run_site_test', 'Run site tests for PWA Kit project', ['PWAV3'], loadServices),
74
- createPlaceholderTool('pwakit_install_agent_rules', 'Install AI agent rules for PWA Kit development', ['PWAV3'], loadServices),
75
- createPlaceholderTool('pwakit_explore_scapi_shop_api', 'Explore SCAPI Shop API endpoints and capabilities', ['PWAV3'], loadServices),
76
- ];
18
+ return [createDeveloperGuidelinesTool(loadServices)];
77
19
  }
78
20
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ import type { McpTool } from '../../utils/index.js';
2
+ import type { Services } from '../../services.js';
3
+ /**
4
+ * Creates the developer guidelines tool for PWA Kit.
5
+ *
6
+ * @param loadServices - Function that loads configuration and returns Services instance
7
+ * @returns The configured MCP tool
8
+ */
9
+ export declare function createDeveloperGuidelinesTool(loadServices: () => Services): McpTool;
@@ -0,0 +1,151 @@
1
+ /*
2
+ * Copyright (c) 2025, Salesforce, Inc.
3
+ * SPDX-License-Identifier: Apache-2
4
+ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+ /**
7
+ * Developer Guidelines tool for PWA Kit.
8
+ *
9
+ * Provides critical development guidelines and best practices for building
10
+ * PWA Kit applications with React, Chakra UI, and Commerce API.
11
+ *
12
+ * @module tools/pwav3/pwa-kit-development-guidelines
13
+ */
14
+ import { readFileSync } from 'node:fs';
15
+ import { createRequire } from 'node:module';
16
+ import path from 'node:path';
17
+ import { z } from 'zod';
18
+ import { createToolAdapter, textResult } from '../adapter.js';
19
+ // Resolve the content directory from the package root
20
+ const require = createRequire(import.meta.url);
21
+ const packageRoot = path.dirname(require.resolve('@salesforce/b2c-dx-mcp/package.json'));
22
+ const CONTENT_DIR = path.join(packageRoot, 'content', 'pwav3');
23
+ /**
24
+ * Section metadata with key and optional description.
25
+ * Single source of truth for all available sections.
26
+ */
27
+ const SECTIONS_METADATA = [
28
+ { key: 'quick-reference', description: null }, // Meta-section, excluded from topics list
29
+ {
30
+ key: 'components',
31
+ description: 'component patterns, Chakra UI, special components (_app, _app-config, _error), React Hooks',
32
+ },
33
+ {
34
+ key: 'data-fetching',
35
+ description: 'commerce-sdk-react hooks, useCustomQuery/useCustomMutation, React Query, custom APIs, caching',
36
+ },
37
+ {
38
+ key: 'routing',
39
+ description: 'Express.js, React Router, configureRoutes, SSR/CSR navigation, withReactQuery, getProps patterns',
40
+ },
41
+ {
42
+ key: 'config',
43
+ description: 'configuration files, environment variables, file precedence, proxy setup, multi-site',
44
+ },
45
+ {
46
+ key: 'state-management',
47
+ description: 'Context API, useReducer, Redux integration, AppConfig methods',
48
+ },
49
+ {
50
+ key: 'extensibility',
51
+ description: 'template extension, ccExtensibility configuration, overrides directory',
52
+ },
53
+ { key: 'testing', description: 'Jest, React Testing Library, MSW, test organization, coverage' },
54
+ {
55
+ key: 'i18n',
56
+ description: 'React Intl, translation extraction/compilation, multi-locale support',
57
+ },
58
+ { key: 'styling', description: 'Chakra UI theming, Emotion CSS-in-JS, responsive design' },
59
+ ];
60
+ /**
61
+ * Derived: array of section keys for validation.
62
+ */
63
+ const _SECTIONS = SECTIONS_METADATA.map((s) => s.key);
64
+ /**
65
+ * Generates the topics list for the tool description.
66
+ * Excludes meta-sections (like quick-reference) that don't have descriptions.
67
+ * @returns Comma-separated list of topics
68
+ */
69
+ function generateTopicsList() {
70
+ return SECTIONS_METADATA.filter((s) => s.description !== null)
71
+ .map((s) => s.description)
72
+ .join(', ');
73
+ }
74
+ /**
75
+ * Detailed section content loaded from markdown files.
76
+ * Built dynamically from SECTIONS_METADATA to avoid duplication.
77
+ */
78
+ const SECTION_CONTENT = Object.fromEntries(SECTIONS_METADATA.map((section) => {
79
+ const filename = `${section.key}.md`;
80
+ const filePath = path.join(CONTENT_DIR, filename);
81
+ const content = readFileSync(filePath, 'utf8');
82
+ return [section.key, content];
83
+ }));
84
+ /**
85
+ * Default sections to return when no sections are specified.
86
+ * Includes quick-reference plus the most critical detailed sections
87
+ * to provide comprehensive guidelines by default.
88
+ */
89
+ const DEFAULT_SECTIONS = ['quick-reference', 'components', 'data-fetching', 'routing'];
90
+ /**
91
+ * Creates the developer guidelines tool for PWA Kit.
92
+ *
93
+ * @param loadServices - Function that loads configuration and returns Services instance
94
+ * @returns The configured MCP tool
95
+ */
96
+ export function createDeveloperGuidelinesTool(loadServices) {
97
+ return createToolAdapter({
98
+ name: 'pwakit_development_guidelines',
99
+ description: 'ESSENTIAL FIRST STEP for PWA Kit v3 development. Returns critical architecture rules, coding standards, and best practices. ' +
100
+ 'Use this tool FIRST before writing any PWA Kit code to understand non-negotiable patterns for React components, ' +
101
+ 'data fetching, routing, configuration, and framework constraints. Returns comprehensive guidelines by default (quick-reference + key sections); ' +
102
+ 'supports retrieving specific topic sections. ' +
103
+ 'CRITICAL INSTRUCTION: ALWAYS present ALL returned content in FULL - DO NOT SUMMARIZE, DO NOT ADD SUMMARIES, ' +
104
+ 'DO NOT ADD OVERVIEWS. The returned content IS the complete answer - display it exactly as provided.',
105
+ toolsets: ['PWAV3'],
106
+ isGA: false,
107
+ requiresInstance: false,
108
+ inputSchema: {
109
+ sections: z
110
+ .array(z.enum([..._SECTIONS]))
111
+ .optional()
112
+ .describe('Optional array of specific sections to retrieve. If not specified, returns comprehensive guidelines ' +
113
+ '(quick-reference, components, data-fetching, routing). ' +
114
+ 'CRITICAL: Present ALL returned content in FULL - DO NOT SUMMARIZE. ' +
115
+ 'Available sections: quick-reference, components, data-fetching, routing, config, state-management, ' +
116
+ 'extensibility, testing, i18n, styling. ' +
117
+ `Topics covered: ${generateTopicsList()}. ` +
118
+ 'Content is complete - present exactly as provided, no summaries.'),
119
+ },
120
+ async execute(args) {
121
+ // Handle empty array case explicitly
122
+ if (args.sections && args.sections.length === 0) {
123
+ return '';
124
+ }
125
+ // Default to comprehensive set of key sections if no sections specified
126
+ const sections = args.sections || DEFAULT_SECTIONS;
127
+ // Multiple sections: combine with separators
128
+ const combinedContent = sections.map((section) => SECTION_CONTENT[section]).join('\n\n---\n\n');
129
+ // Apply instructions for all multi-section responses to ensure full content display
130
+ const isMultiSection = sections.length > 1;
131
+ // Prepend explicit instruction to present full content (not summarized)
132
+ const fullContentInstruction = isMultiSection
133
+ ? '⚠️ CRITICAL: Display the FULL content below. DO NOT summarize, condense, or add overviews.\n\n' +
134
+ '📋 PWA KIT DEVELOPMENT GUIDELINES\n\n' +
135
+ '---\n\n'
136
+ : '';
137
+ // Add footer instruction to reinforce the message for multi-section responses
138
+ const footerInstruction = isMultiSection
139
+ ? '\n\n---\n\n⚠️ END OF CONTENT - Full content displayed above. Do not add summaries.\n'
140
+ : '';
141
+ // For single sections, return directly (backward compatible)
142
+ // For multiple sections, wrap with instructions
143
+ if (sections.length === 1) {
144
+ return SECTION_CONTENT[sections[0]];
145
+ }
146
+ return fullContentInstruction + combinedContent + footerInstruction;
147
+ },
148
+ formatOutput: (output) => textResult(output),
149
+ }, loadServices);
150
+ }
151
+ //# sourceMappingURL=pwa-kit-development-guidelines.js.map
@@ -2,7 +2,7 @@
2
2
  * SCAPI toolset for B2C Commerce.
3
3
  *
4
4
  * This toolset provides MCP tools for Salesforce Commerce API (SCAPI) discovery and exploration.
5
- * Includes both standard SCAPI schemas and custom API status tools.
5
+ * Includes standard SCAPI schemas, custom API status, and custom API scaffold tools.
6
6
  *
7
7
  * @module tools/scapi
8
8
  */
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { createScapiSchemasListTool } from './scapi-schemas-list.js';
7
7
  import { createScapiCustomApisStatusTool } from './scapi-custom-apis-status.js';
8
+ import { createScaffoldCustomApiTool } from './scapi-custom-api-scaffold.js';
8
9
  /**
9
10
  * Creates all tools for the SCAPI toolset.
10
11
  *
@@ -12,6 +13,10 @@ import { createScapiCustomApisStatusTool } from './scapi-custom-apis-status.js';
12
13
  * @returns Array of MCP tools
13
14
  */
14
15
  export function createScapiTools(loadServices) {
15
- return [createScapiSchemasListTool(loadServices), createScapiCustomApisStatusTool(loadServices)];
16
+ return [
17
+ createScapiSchemasListTool(loadServices),
18
+ createScapiCustomApisStatusTool(loadServices),
19
+ createScaffoldCustomApiTool(loadServices),
20
+ ];
16
21
  }
17
22
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,60 @@
1
+ import type { Services } from '../../services.js';
2
+ import type { McpTool } from '../../utils/index.js';
3
+ import type { Scaffold, ResolvedParameters, ResolveParametersOptions } from '@salesforce/b2c-tooling-sdk/scaffold';
4
+ /** Optional overrides for testing (scaffold not found, missing required). */
5
+ export interface ScaffoldCustomApiExecuteOverrides {
6
+ getScaffold?: (id: string, opts: {
7
+ projectRoot: string;
8
+ }) => Promise<null | Scaffold>;
9
+ resolveScaffoldParameters?: (scaffold: Scaffold, opts: ResolveParametersOptions) => Promise<ResolvedParameters>;
10
+ }
11
+ /**
12
+ * Input schema for scapi_custom_api_scaffold tool.
13
+ * Parameters match the custom-api scaffold: apiName, apiType, cartridgeName, etc.
14
+ */
15
+ interface ScaffoldCustomApiInput {
16
+ /** API name (kebab-case, e.g. my-products). Required. */
17
+ apiName: string;
18
+ /** Cartridge name that will contain the API. Optional; defaults to first cartridge found in project. */
19
+ cartridgeName?: string;
20
+ /** API type: admin (no siteId) or shopper (siteId, customer-facing). Default: shopper */
21
+ apiType?: 'admin' | 'shopper';
22
+ /** Short description of the API. Default: "A custom B2C Commerce API" */
23
+ apiDescription?: string;
24
+ /** Project root for cartridge discovery and output. Default: MCP project directory */
25
+ projectRoot?: string;
26
+ /** Output directory override. Default: scaffold default or project root */
27
+ outputDir?: string;
28
+ }
29
+ /**
30
+ * Output schema for scapi_custom_api_scaffold tool.
31
+ */
32
+ interface ScaffoldCustomApiOutput {
33
+ scaffold: string;
34
+ outputDir: string;
35
+ dryRun: boolean;
36
+ files: Array<{
37
+ path: string;
38
+ action: string;
39
+ skipReason?: string;
40
+ }>;
41
+ postInstructions?: string;
42
+ error?: string;
43
+ }
44
+ /**
45
+ * Core execute logic for the custom API scaffold tool.
46
+ * Exported for tests so we can inject getScaffold / resolveScaffoldParameters and cover error branches.
47
+ */
48
+ export declare function executeScaffoldCustomApi(args: ScaffoldCustomApiInput, services: Services, overrides?: ScaffoldCustomApiExecuteOverrides): Promise<ScaffoldCustomApiOutput>;
49
+ /**
50
+ * Creates the scapi_custom_api_scaffold tool.
51
+ *
52
+ * Uses @salesforce/b2c-tooling-sdk scaffold: registry, resolveScaffoldParameters,
53
+ * resolveOutputDirectory, generateFromScaffold. cartridgeName must be a cartridge
54
+ * discovered under projectRoot (e.g. from .project or cartridges/).
55
+ *
56
+ * @param loadServices - Function that returns Services (used by adapter on each call).
57
+ * @param executeOverrides - Optional overrides for testing (getScaffold, resolveScaffoldParameters).
58
+ */
59
+ export declare function createScaffoldCustomApiTool(loadServices: () => Services, executeOverrides?: ScaffoldCustomApiExecuteOverrides): McpTool;
60
+ export {};
@@ -0,0 +1,175 @@
1
+ /*
2
+ * Copyright (c) 2025, Salesforce, Inc.
3
+ * SPDX-License-Identifier: Apache-2
4
+ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+ /**
7
+ * SCAPI Custom API Scaffold tool.
8
+ *
9
+ * Generates a new custom SCAPI endpoint using the SDK's custom-api scaffold
10
+ * (schema.yaml, api.json, script.js).
11
+ *
12
+ * @module tools/scapi/scapi-custom-api-scaffold
13
+ */
14
+ import { z } from 'zod';
15
+ import { createToolAdapter, jsonResult, errorResult } from '../adapter.js';
16
+ import { createScaffoldRegistry, generateFromScaffold, resolveScaffoldParameters, resolveOutputDirectory, } from '@salesforce/b2c-tooling-sdk/scaffold';
17
+ import { findCartridges } from '@salesforce/b2c-tooling-sdk/operations/code';
18
+ const CUSTOM_API_SCAFFOLD_ID = 'custom-api';
19
+ /**
20
+ * Core execute logic for the custom API scaffold tool.
21
+ * Exported for tests so we can inject getScaffold / resolveScaffoldParameters and cover error branches.
22
+ */
23
+ export async function executeScaffoldCustomApi(args, services, overrides) {
24
+ const projectRoot = services.resolveWithProjectDirectory(args.projectRoot);
25
+ const getScaffold = overrides?.getScaffold ??
26
+ (async (id, opts) => {
27
+ const registry = createScaffoldRegistry();
28
+ return registry.getScaffold(id, opts);
29
+ });
30
+ const scaffold = await getScaffold(CUSTOM_API_SCAFFOLD_ID, { projectRoot });
31
+ if (!scaffold) {
32
+ return {
33
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
34
+ outputDir: projectRoot,
35
+ dryRun: false,
36
+ files: [],
37
+ error: `Scaffold not found: ${CUSTOM_API_SCAFFOLD_ID}. Ensure @salesforce/b2c-tooling-sdk is installed.`,
38
+ };
39
+ }
40
+ const cartridges = findCartridges(projectRoot);
41
+ if (cartridges.length === 0) {
42
+ return {
43
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
44
+ outputDir: projectRoot,
45
+ dryRun: false,
46
+ files: [],
47
+ error: 'No cartridges found in project. Custom API scaffold requires an existing cartridge. Create a cartridge first: use `b2c scaffold cartridge --name app_custom`, or manually create a directory with a `.project` file (e.g., cartridges/app_custom/.project).',
48
+ };
49
+ }
50
+ let cartridgeName = args.cartridgeName;
51
+ if (!cartridgeName) {
52
+ cartridgeName = cartridges[0].name;
53
+ }
54
+ const providedVariables = {
55
+ apiName: args.apiName,
56
+ cartridgeName,
57
+ includeExampleEndpoints: true,
58
+ };
59
+ if (args.apiType !== undefined)
60
+ providedVariables.apiType = args.apiType;
61
+ if (args.apiDescription !== undefined)
62
+ providedVariables.apiDescription = args.apiDescription;
63
+ const resolveParams = overrides?.resolveScaffoldParameters ?? resolveScaffoldParameters;
64
+ const resolved = await resolveParams(scaffold, {
65
+ providedVariables,
66
+ projectRoot,
67
+ useDefaults: true,
68
+ });
69
+ if (resolved.errors.length > 0) {
70
+ const message = resolved.errors.map((e) => `${e.parameter}: ${e.message}`).join('; ');
71
+ return {
72
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
73
+ outputDir: projectRoot,
74
+ dryRun: false,
75
+ files: [],
76
+ error: `Parameter validation failed: ${message}`,
77
+ };
78
+ }
79
+ const missingRequired = resolved.missingParameters.filter((p) => p.required);
80
+ if (missingRequired.length > 0) {
81
+ return {
82
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
83
+ outputDir: projectRoot,
84
+ dryRun: false,
85
+ files: [],
86
+ error: `Missing required parameter: ${missingRequired[0].name}. For cartridgeName, ensure the cartridge exists in the project (under projectRoot).`,
87
+ };
88
+ }
89
+ const outputDir = resolveOutputDirectory({
90
+ outputDir: args.outputDir,
91
+ scaffold,
92
+ projectRoot,
93
+ });
94
+ try {
95
+ const result = await generateFromScaffold(scaffold, {
96
+ outputDir,
97
+ variables: resolved.variables,
98
+ dryRun: false,
99
+ force: false,
100
+ });
101
+ return {
102
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
103
+ outputDir,
104
+ dryRun: result.dryRun,
105
+ files: result.files.map((f) => ({
106
+ path: f.path,
107
+ action: f.action,
108
+ skipReason: f.skipReason,
109
+ })),
110
+ postInstructions: result.postInstructions,
111
+ };
112
+ }
113
+ catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return {
116
+ scaffold: CUSTOM_API_SCAFFOLD_ID,
117
+ outputDir,
118
+ dryRun: false,
119
+ files: [],
120
+ error: `Scaffold generation failed: ${message}`,
121
+ };
122
+ }
123
+ }
124
+ /**
125
+ * Creates the scapi_custom_api_scaffold tool.
126
+ *
127
+ * Uses @salesforce/b2c-tooling-sdk scaffold: registry, resolveScaffoldParameters,
128
+ * resolveOutputDirectory, generateFromScaffold. cartridgeName must be a cartridge
129
+ * discovered under projectRoot (e.g. from .project or cartridges/).
130
+ *
131
+ * @param loadServices - Function that returns Services (used by adapter on each call).
132
+ * @param executeOverrides - Optional overrides for testing (getScaffold, resolveScaffoldParameters).
133
+ */
134
+ export function createScaffoldCustomApiTool(loadServices, executeOverrides) {
135
+ return createToolAdapter({
136
+ name: 'scapi_custom_api_scaffold',
137
+ description: `Generate a new custom SCAPI endpoint (OAS 3.0 schema, api.json, script.js) in an existing cartridge. \
138
+ Required: apiName (kebab-case). Optional: cartridgeName (defaults to first cartridge found in project), apiType (shopper|admin) default to shopper, \
139
+ apiDescription, projectRoot, outputDir.`,
140
+ toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
141
+ isGA: false,
142
+ requiresInstance: false,
143
+ inputSchema: {
144
+ apiName: z
145
+ .string()
146
+ .min(1)
147
+ .describe('API name in kebab-case (e.g. my-products). Must start with lowercase letter, only letters, numbers, hyphens.'),
148
+ cartridgeName: z
149
+ .string()
150
+ .min(1)
151
+ .nullish()
152
+ .describe('Cartridge name that will contain the API. Optional; omit to use the first cartridge found under project root).'),
153
+ apiType: z
154
+ .enum(['admin', 'shopper'])
155
+ .optional()
156
+ .describe('Admin (no siteId) or shopper (siteId, customer-facing). Default: shopper'),
157
+ apiDescription: z.string().optional().describe('Short description of the API.'),
158
+ projectRoot: z
159
+ .string()
160
+ .nullish()
161
+ .describe('Project root for cartridge discovery. Default: project directory. Set to override the project directory.'),
162
+ outputDir: z.string().optional().describe('Output directory override. Default: project root'),
163
+ },
164
+ async execute(args, { services }) {
165
+ return executeScaffoldCustomApi(args, services, executeOverrides);
166
+ },
167
+ formatOutput(output) {
168
+ if (output.error) {
169
+ return errorResult(output.error);
170
+ }
171
+ return jsonResult(output);
172
+ },
173
+ }, loadServices);
174
+ }
175
+ //# sourceMappingURL=scapi-custom-api-scaffold.js.map