@salesforce/b2c-dx-mcp 1.10.1 → 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.
- package/README.md +15 -62
- package/dist/commands/mcp.d.ts +14 -7
- package/dist/commands/mcp.js +91 -12
- package/dist/registry.d.ts +3 -3
- package/dist/registry.js +7 -14
- package/dist/server-context.d.ts +1 -1
- package/dist/server-context.js +1 -1
- package/dist/services.d.ts +29 -1
- package/dist/services.js +48 -1
- package/dist/tools/adapter.d.ts +25 -1
- package/dist/tools/adapter.js +53 -8
- package/dist/tools/cartridges/index.js +14 -3
- package/dist/tools/diagnostics/config-inspect.js +3 -2
- package/dist/tools/diagnostics/debug-list-sessions.js +1 -1
- package/dist/tools/diagnostics/debug-start-session.js +22 -9
- package/dist/tools/diagnostics/log-watch-registry.d.ts +3 -0
- package/dist/tools/diagnostics/log-watch-registry.js +1 -0
- package/dist/tools/diagnostics/logs-watch-list.js +1 -0
- package/dist/tools/diagnostics/logs-watch-start.js +6 -1
- package/dist/tools/diagnostics/mrt-log-watch-registry.d.ts +3 -0
- package/dist/tools/diagnostics/mrt-log-watch-registry.js +0 -0
- package/dist/tools/diagnostics/mrt-logs-watch-list.js +1 -0
- package/dist/tools/diagnostics/mrt-logs-watch-start.js +7 -1
- package/dist/tools/diagnostics/session-registry.d.ts +3 -0
- package/dist/tools/diagnostics/session-registry.js +4 -3
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- package/dist/tools/mrt/index.js +13 -3
- package/dist/tools/project-context.d.ts +53 -0
- package/dist/tools/project-context.js +55 -0
- package/dist/tools/scapi/metrics-get.js +1 -0
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +8 -1
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +41 -7
- package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -0
- package/dist/tools/scapi/scapi-schemas-list.js +1 -0
- package/dist/utils/constants.d.ts +2 -13
- package/dist/utils/constants.js +1 -20
- package/oclif.manifest.json +2 -2
- package/package.json +3 -3
- package/content/sfnext/auth.md +0 -62
- package/content/sfnext/components.md +0 -123
- package/content/sfnext/config.md +0 -180
- package/content/sfnext/data-fetching.md +0 -323
- package/content/sfnext/extensions.md +0 -80
- package/content/sfnext/i18n.md +0 -121
- package/content/sfnext/page-designer.md +0 -78
- package/content/sfnext/performance.md +0 -80
- package/content/sfnext/pitfalls.md +0 -141
- package/content/sfnext/quick-reference.md +0 -226
- package/content/sfnext/state-management.md +0 -75
- package/content/sfnext/styling.md +0 -51
- package/content/sfnext/testing.md +0 -232
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +0 -24
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +0 -53
- package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +0 -42
- package/dist/tools/storefrontnext/figma/figma-to-component/index.js +0 -326
- package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +0 -40
- package/dist/tools/storefrontnext/figma/generate-component/decision.js +0 -312
- package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +0 -9
- package/dist/tools/storefrontnext/figma/generate-component/formatter.js +0 -92
- package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +0 -114
- package/dist/tools/storefrontnext/figma/generate-component/index.js +0 -99
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +0 -71
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +0 -260
- package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +0 -61
- package/dist/tools/storefrontnext/figma/map-tokens/index.js +0 -235
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +0 -65
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +0 -268
- package/dist/tools/storefrontnext/index.d.ts +0 -30
- package/dist/tools/storefrontnext/index.js +0 -28
- package/dist/tools/storefrontnext/page-designer-decorator/analyzer.d.ts +0 -169
- package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +0 -567
- package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +0 -252
- package/dist/tools/storefrontnext/page-designer-decorator/index.js +0 -617
- package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.d.ts +0 -8
- package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.js +0 -65
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.d.ts +0 -13
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.js +0 -87
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.d.ts +0 -4
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.js +0 -55
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.d.ts +0 -22
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.js +0 -109
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.d.ts +0 -21
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.js +0 -60
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.d.ts +0 -27
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.js +0 -68
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.d.ts +0 -4
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.js +0 -65
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.d.ts +0 -11
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.js +0 -92
- package/dist/tools/storefrontnext/page-designer-decorator/rules.d.ts +0 -51
- package/dist/tools/storefrontnext/page-designer-decorator/rules.js +0 -70
- package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.d.ts +0 -116
- package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.js +0 -350
- package/dist/tools/storefrontnext/sfnext-development-guidelines.d.ts +0 -9
- package/dist/tools/storefrontnext/sfnext-development-guidelines.js +0 -141
- package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +0 -92
- package/dist/tools/storefrontnext/site-theming/color-contrast.js +0 -186
- package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +0 -16
- package/dist/tools/storefrontnext/site-theming/color-mapping.js +0 -131
- package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +0 -11
- package/dist/tools/storefrontnext/site-theming/guidance-merger.js +0 -78
- package/dist/tools/storefrontnext/site-theming/index.d.ts +0 -14
- package/dist/tools/storefrontnext/site-theming/index.js +0 -123
- package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +0 -16
- package/dist/tools/storefrontnext/site-theming/response-builder.js +0 -316
- package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +0 -62
- package/dist/tools/storefrontnext/site-theming/theming-store.js +0 -417
- package/dist/tools/storefrontnext/site-theming/types.d.ts +0 -35
- package/dist/tools/storefrontnext/site-theming/types.js +0 -7
package/dist/tools/adapter.js
CHANGED
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
import { z } from 'zod';
|
|
73
|
+
import { createProjectContextInputSchema, } from './project-context.js';
|
|
73
74
|
/**
|
|
74
75
|
* Creates a text-only success result.
|
|
75
76
|
*
|
|
@@ -120,6 +121,25 @@ export function jsonResult(data, indent = 2) {
|
|
|
120
121
|
content: [{ type: 'text', text: JSON.stringify(data, null, indent) }],
|
|
121
122
|
};
|
|
122
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
|
+
}
|
|
123
143
|
/**
|
|
124
144
|
* Formats Zod validation errors into a human-readable string.
|
|
125
145
|
*
|
|
@@ -169,13 +189,24 @@ function formatZodErrors(error) {
|
|
|
169
189
|
* ```
|
|
170
190
|
*/
|
|
171
191
|
export function createToolAdapter(options, loadServices, serverContext) {
|
|
172
|
-
const { name, description, inputSchema, toolsets, isGA = true, requiresInstance = false, requiresMrtAuth = false, execute, formatOutput, } = options;
|
|
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
|
+
}
|
|
203
|
+
: inputSchema;
|
|
173
204
|
// Create Zod schema from inputSchema definition
|
|
174
|
-
const zodSchema = z.object(
|
|
205
|
+
const zodSchema = z.object(effectiveInputSchema);
|
|
175
206
|
return {
|
|
176
207
|
name,
|
|
177
208
|
description,
|
|
178
|
-
inputSchema,
|
|
209
|
+
inputSchema: effectiveInputSchema,
|
|
179
210
|
toolsets,
|
|
180
211
|
isGA,
|
|
181
212
|
async handler(rawArgs) {
|
|
@@ -185,14 +216,21 @@ export function createToolAdapter(options, loadServices, serverContext) {
|
|
|
185
216
|
return errorResult(`Invalid input: ${formatZodErrors(parseResult.error)}`);
|
|
186
217
|
}
|
|
187
218
|
const args = parseResult.data;
|
|
219
|
+
let resolution;
|
|
188
220
|
try {
|
|
189
221
|
// 2. Load Services to get fresh configuration (re-reads config files)
|
|
190
|
-
const
|
|
222
|
+
const projectContext = projectContextKind ? args : undefined;
|
|
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;
|
|
191
229
|
// 3. Get B2CInstance if required (loaded on each call)
|
|
192
230
|
let b2cInstance;
|
|
193
231
|
if (requiresInstance) {
|
|
194
232
|
if (!services.b2cInstance) {
|
|
195
|
-
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);
|
|
196
234
|
}
|
|
197
235
|
b2cInstance = services.b2cInstance;
|
|
198
236
|
}
|
|
@@ -200,7 +238,7 @@ export function createToolAdapter(options, loadServices, serverContext) {
|
|
|
200
238
|
let mrtConfig;
|
|
201
239
|
if (requiresMrtAuth) {
|
|
202
240
|
if (!services.mrtConfig.auth) {
|
|
203
|
-
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);
|
|
204
242
|
}
|
|
205
243
|
mrtConfig = {
|
|
206
244
|
auth: services.mrtConfig.auth,
|
|
@@ -215,15 +253,22 @@ export function createToolAdapter(options, loadServices, serverContext) {
|
|
|
215
253
|
mrtConfig,
|
|
216
254
|
services,
|
|
217
255
|
serverContext,
|
|
256
|
+
resolution: executionResolution,
|
|
257
|
+
setResolvedDirectory(name, value) {
|
|
258
|
+
executionResolution.directories ??= {};
|
|
259
|
+
executionResolution.directories[name] = value;
|
|
260
|
+
},
|
|
218
261
|
};
|
|
219
262
|
const output = await execute(args, context);
|
|
220
263
|
// 6. Format output
|
|
221
|
-
|
|
264
|
+
const result = formatOutput(output);
|
|
265
|
+
return resolution ? attachResolution(result, executionResolution) : result;
|
|
222
266
|
}
|
|
223
267
|
catch (error) {
|
|
224
268
|
// Handle execution errors
|
|
225
269
|
const message = error instanceof Error ? error.message : String(error);
|
|
226
|
-
|
|
270
|
+
const result = errorResult(`Execution error: ${message}`);
|
|
271
|
+
return resolution ? attachResolution(result, resolution) : result;
|
|
227
272
|
}
|
|
228
273
|
},
|
|
229
274
|
};
|
|
@@ -44,12 +44,16 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
44
44
|
toolsets: ['CARTRIDGES'],
|
|
45
45
|
isGA: true,
|
|
46
46
|
requiresInstance: true,
|
|
47
|
+
usesProjectContext: true,
|
|
47
48
|
inputSchema: {
|
|
49
|
+
cartridgeDirectory: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('Optional cartridge discovery root. Relative paths resolve from projectDirectory. Defaults to projectDirectory.'),
|
|
48
53
|
directory: z
|
|
49
54
|
.string()
|
|
50
55
|
.optional()
|
|
51
|
-
.describe('
|
|
52
|
-
'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.'),
|
|
53
57
|
cartridges: z
|
|
54
58
|
.array(z.string())
|
|
55
59
|
.optional()
|
|
@@ -87,7 +91,13 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
87
91
|
instance.config.codeVersion = codeVersion;
|
|
88
92
|
}
|
|
89
93
|
// Resolve directory path: relative paths are resolved relative to project directory, absolute paths are used as-is
|
|
90
|
-
const
|
|
94
|
+
const projectDirectory = context.services.resolveProjectDirectory(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
|
+
});
|
|
91
101
|
// Parse options
|
|
92
102
|
const options = {
|
|
93
103
|
include: args.cartridges,
|
|
@@ -106,6 +116,7 @@ function createCartridgeDeployTool(loadServices, injections) {
|
|
|
106
116
|
const result = await findAndDeployCartridgesFn(instance, directory, options);
|
|
107
117
|
return {
|
|
108
118
|
...result,
|
|
119
|
+
projectDirectory,
|
|
109
120
|
resolvedDirectory: directory,
|
|
110
121
|
postInstructions: CARTRIDGE_PATH_REMINDER,
|
|
111
122
|
};
|
|
@@ -20,11 +20,12 @@ export function createConfigInspectTool(loadServices) {
|
|
|
20
20
|
name: 'config_inspect',
|
|
21
21
|
description: 'Inspect the resolved B2C Commerce configuration the MCP server is using — instance hostname, auth, SCAPI, MRT, and other settings — along with which source (dw.json, environment variables, flags) provided each value. ' +
|
|
22
22
|
'Secrets (passwords, client secrets, API keys) are redacted by default. ' +
|
|
23
|
-
'
|
|
23
|
+
'Pass projectDirectory, configPath, and/or instanceName to inspect the same project, configuration catalog, and named instance another tool would use. The detailed source graph is supplemented by the same compact resolution provenance returned by other configuration-aware tools. ' +
|
|
24
24
|
'Use this first when configuration seems wrong, auth is failing, or the server appears to be operating in the wrong directory.',
|
|
25
25
|
toolsets: ['DIAGNOSTICS'],
|
|
26
26
|
isGA: true,
|
|
27
27
|
requiresInstance: false,
|
|
28
|
+
usesConfigurationContext: true,
|
|
28
29
|
inputSchema: {
|
|
29
30
|
unmask: z
|
|
30
31
|
.boolean()
|
|
@@ -33,7 +34,7 @@ export function createConfigInspectTool(loadServices) {
|
|
|
33
34
|
},
|
|
34
35
|
async execute(args, { services }) {
|
|
35
36
|
const resolved = services.getResolvedConfig();
|
|
36
|
-
const projectDirectory = services.resolveProjectDirectory();
|
|
37
|
+
const projectDirectory = services.resolveProjectDirectory(args.projectDirectory);
|
|
37
38
|
return {
|
|
38
39
|
config: redactConfigValues(resolved.values, { unmask: args.unmask ?? false }),
|
|
39
40
|
projectDirectory,
|
|
@@ -22,7 +22,6 @@ export function createDebugListSessionsTool(loadServices, serverContext) {
|
|
|
22
22
|
return {
|
|
23
23
|
session_id: entry.sessionId,
|
|
24
24
|
hostname: entry.hostname,
|
|
25
|
-
client_id: entry.clientId,
|
|
26
25
|
halted_threads: entry.manager
|
|
27
26
|
.getKnownThreads()
|
|
28
27
|
.filter((t) => t.status === 'halted')
|
|
@@ -31,6 +30,7 @@ export function createDebugListSessionsTool(loadServices, serverContext) {
|
|
|
31
30
|
session_cookie: dwsid ? { name: 'dwsid', value: dwsid } : null,
|
|
32
31
|
created_at: new Date(entry.createdAt).toISOString(),
|
|
33
32
|
last_activity_at: new Date(entry.lastActivityAt).toISOString(),
|
|
33
|
+
resolution: entry.resolution,
|
|
34
34
|
};
|
|
35
35
|
}),
|
|
36
36
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
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
|
+
import { randomUUID } from 'node:crypto';
|
|
6
7
|
import { z } from 'zod';
|
|
7
8
|
import { createToolAdapter, jsonResult } from '../adapter.js';
|
|
8
9
|
import { DebugSessionManager, createSourceMapper, } from '@salesforce/b2c-tooling-sdk/operations/debug';
|
|
@@ -12,19 +13,17 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
12
13
|
return createToolAdapter({
|
|
13
14
|
name: 'debug_start_session',
|
|
14
15
|
description: 'Start a script debugger session on a B2C Commerce instance to debug SFRA controllers, custom API scripts, hooks, jobs, or any server-side script. ' +
|
|
16
|
+
'Uses projectDirectory to load project configuration and discover cartridges. cartridgeDirectory may override only the cartridge discovery/source-mapping root. ' +
|
|
15
17
|
'Returns a session_id for use with other debug tools, plus discovered cartridge mappings. ' +
|
|
16
18
|
'WARNING: Debug sessions halt remote request threads on the instance. Always call debug_end_session when finished.',
|
|
17
19
|
toolsets: ['CARTRIDGES', 'DIAGNOSTICS', 'SCAPI'],
|
|
18
20
|
inputSchema: {
|
|
19
|
-
|
|
21
|
+
cartridgeDirectory: z
|
|
20
22
|
.string()
|
|
21
23
|
.optional()
|
|
22
|
-
.describe('
|
|
23
|
-
client_id: z
|
|
24
|
-
.string()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe('Client ID for the debugger API. Defaults to "b2c-cli". Use a different ID to run concurrent sessions on the same host.'),
|
|
24
|
+
.describe('Optional cartridge discovery and debugger source-mapping root. Relative paths resolve from projectDirectory. Defaults to projectDirectory.'),
|
|
27
25
|
},
|
|
26
|
+
usesConfigurationContext: true,
|
|
28
27
|
async execute(args, context) {
|
|
29
28
|
const registry = getRegistry(context);
|
|
30
29
|
const credentials = context.services.getBasicAuthCredentials();
|
|
@@ -33,8 +32,13 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
33
32
|
'Set via SFCC_SERVER/SFCC_USERNAME/SFCC_PASSWORD env vars, or dw.json.');
|
|
34
33
|
}
|
|
35
34
|
const { hostname, username, password } = credentials;
|
|
36
|
-
const clientId =
|
|
37
|
-
const
|
|
35
|
+
const clientId = `b2c-dx-mcp-${randomUUID()}`;
|
|
36
|
+
const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
|
|
37
|
+
const cartridgeDir = context.services.resolveWithProjectDirectory(args.cartridgeDirectory, args.projectDirectory);
|
|
38
|
+
context.setResolvedDirectory('cartridgeDirectory', {
|
|
39
|
+
path: cartridgeDir,
|
|
40
|
+
source: args.cartridgeDirectory ? 'argument' : 'projectDirectory',
|
|
41
|
+
});
|
|
38
42
|
const cartridges = findCartridges(cartridgeDir);
|
|
39
43
|
const warnings = [];
|
|
40
44
|
if (cartridges.length === 0) {
|
|
@@ -55,7 +59,14 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
55
59
|
};
|
|
56
60
|
const manager = new DebugSessionManager({ hostname, username, password, clientId, cartridgeRoots: cartridges }, callbacks);
|
|
57
61
|
await manager.connect();
|
|
58
|
-
const entry = registry.registerSession({
|
|
62
|
+
const entry = registry.registerSession({
|
|
63
|
+
hostname,
|
|
64
|
+
clientId,
|
|
65
|
+
manager,
|
|
66
|
+
sourceMapper,
|
|
67
|
+
cartridges,
|
|
68
|
+
resolution: structuredClone(context.resolution),
|
|
69
|
+
});
|
|
59
70
|
const cartridgeMappings = {};
|
|
60
71
|
for (const c of cartridges)
|
|
61
72
|
cartridgeMappings[c.name] = c.src;
|
|
@@ -70,6 +81,8 @@ export function createDebugStartSessionTool(loadServices, serverContext) {
|
|
|
70
81
|
cartridge_mappings: cartridgeMappings,
|
|
71
82
|
session_cookie: dwsid ? { name: 'dwsid', value: dwsid } : null,
|
|
72
83
|
warnings,
|
|
84
|
+
projectDirectory,
|
|
85
|
+
cartridgeDirectory: cartridgeDir,
|
|
73
86
|
};
|
|
74
87
|
},
|
|
75
88
|
formatOutput: (output) => jsonResult(output),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LogEntry, LogFile, TailLogsResult } from '@salesforce/b2c-tooling-sdk/operations/logs';
|
|
2
2
|
import type { ToolExecutionContext } from '../adapter.js';
|
|
3
|
+
import type { ToolResolution } from '../project-context.js';
|
|
3
4
|
/** Maximum number of buffered entries before oldest are evicted. */
|
|
4
5
|
export declare const DEFAULT_BUFFER_CAP = 5000;
|
|
5
6
|
/**
|
|
@@ -38,6 +39,7 @@ export interface LogWatchEntry {
|
|
|
38
39
|
createdAt: number;
|
|
39
40
|
lastActivityAt: number;
|
|
40
41
|
stopped: boolean;
|
|
42
|
+
resolution?: ToolResolution;
|
|
41
43
|
}
|
|
42
44
|
export interface RegisterWatchOptions {
|
|
43
45
|
hostname: string;
|
|
@@ -45,6 +47,7 @@ export interface RegisterWatchOptions {
|
|
|
45
47
|
tailResult: TailLogsResult;
|
|
46
48
|
bufferCap?: number;
|
|
47
49
|
bufferBytesCap?: number;
|
|
50
|
+
resolution?: ToolResolution;
|
|
48
51
|
}
|
|
49
52
|
export declare class LogWatchRegistry {
|
|
50
53
|
private cleanupTimer;
|
|
@@ -97,7 +97,12 @@ export function createLogsWatchStartTool(loadServices, serverContext, injections
|
|
|
97
97
|
// it isn't orphaned (it would otherwise poll WebDAV until process exit).
|
|
98
98
|
let entry;
|
|
99
99
|
try {
|
|
100
|
-
entry = registry.registerWatch({
|
|
100
|
+
entry = registry.registerWatch({
|
|
101
|
+
hostname,
|
|
102
|
+
prefixes,
|
|
103
|
+
tailResult,
|
|
104
|
+
resolution: structuredClone(context.resolution),
|
|
105
|
+
});
|
|
101
106
|
}
|
|
102
107
|
catch (error) {
|
|
103
108
|
await tailResult.stop().catch(() => { });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MrtLogEntry, TailMrtLogsResult } from '@salesforce/b2c-tooling-sdk/operations/mrt';
|
|
2
2
|
import type { ToolExecutionContext } from '../adapter.js';
|
|
3
|
+
import type { ToolResolution } from '../project-context.js';
|
|
3
4
|
/** Maximum number of buffered entries before oldest are evicted. */
|
|
4
5
|
export declare const DEFAULT_BUFFER_CAP = 5000;
|
|
5
6
|
/**
|
|
@@ -42,6 +43,7 @@ export interface MrtLogWatchEntry {
|
|
|
42
43
|
* watch keeps its buffered entries until drained or idle-reaped.
|
|
43
44
|
*/
|
|
44
45
|
stopped: boolean;
|
|
46
|
+
resolution?: ToolResolution;
|
|
45
47
|
}
|
|
46
48
|
export interface RegisterMrtWatchOptions {
|
|
47
49
|
project: string;
|
|
@@ -50,6 +52,7 @@ export interface RegisterMrtWatchOptions {
|
|
|
50
52
|
tailResult: TailMrtLogsResult;
|
|
51
53
|
bufferCap?: number;
|
|
52
54
|
bufferBytesCap?: number;
|
|
55
|
+
resolution?: ToolResolution;
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
55
58
|
* Stable dedup key for an MRT log watch. A developer may tail several
|
|
Binary file
|
|
@@ -113,7 +113,13 @@ export function createMrtLogsWatchStartTool(loadServices, serverContext, injecti
|
|
|
113
113
|
// exit).
|
|
114
114
|
let entry;
|
|
115
115
|
try {
|
|
116
|
-
entry = registry.registerWatch({
|
|
116
|
+
entry = registry.registerWatch({
|
|
117
|
+
project,
|
|
118
|
+
environment,
|
|
119
|
+
origin,
|
|
120
|
+
tailResult,
|
|
121
|
+
resolution: structuredClone(context.resolution),
|
|
122
|
+
});
|
|
117
123
|
}
|
|
118
124
|
catch (error) {
|
|
119
125
|
tailResult.stop();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DebugSessionManager, SourceMapper, SdapiBreakpoint, SdapiScriptThread } from '@salesforce/b2c-tooling-sdk/operations/debug';
|
|
2
2
|
import type { CartridgeMapping } from '@salesforce/b2c-tooling-sdk/operations/code';
|
|
3
3
|
import type { ToolExecutionContext } from '../adapter.js';
|
|
4
|
+
import type { ToolResolution } from '../project-context.js';
|
|
4
5
|
export interface HaltWaiter {
|
|
5
6
|
resolve: (thread: SdapiScriptThread) => void;
|
|
6
7
|
reject: (error: Error) => void;
|
|
@@ -17,6 +18,7 @@ export interface DebugSessionEntry {
|
|
|
17
18
|
haltWaiters: HaltWaiter[];
|
|
18
19
|
createdAt: number;
|
|
19
20
|
lastActivityAt: number;
|
|
21
|
+
resolution?: ToolResolution;
|
|
20
22
|
}
|
|
21
23
|
export interface RegisterSessionOptions {
|
|
22
24
|
hostname: string;
|
|
@@ -24,6 +26,7 @@ export interface RegisterSessionOptions {
|
|
|
24
26
|
manager: DebugSessionManager;
|
|
25
27
|
sourceMapper: SourceMapper;
|
|
26
28
|
cartridges: CartridgeMapping[];
|
|
29
|
+
resolution?: ToolResolution;
|
|
27
30
|
}
|
|
28
31
|
export declare class DebugSessionRegistry {
|
|
29
32
|
private cleanupTimer;
|
|
@@ -64,12 +64,12 @@ export class DebugSessionRegistry {
|
|
|
64
64
|
return [...this.sessions.values()];
|
|
65
65
|
}
|
|
66
66
|
registerSession(opts) {
|
|
67
|
-
const { hostname, clientId, manager, sourceMapper, cartridges } = opts;
|
|
67
|
+
const { hostname, clientId, manager, sourceMapper, cartridges, resolution } = opts;
|
|
68
68
|
const existing = this.findByHostAndClientId(hostname, clientId);
|
|
69
69
|
if (existing) {
|
|
70
|
-
throw new Error(`A debug session already exists for ${hostname}
|
|
70
|
+
throw new Error(`A debug session already exists for ${hostname} ` +
|
|
71
71
|
`(session_id: "${existing.sessionId}"). ` +
|
|
72
|
-
`End it with debug_end_session first
|
|
72
|
+
`End it with debug_end_session first.`);
|
|
73
73
|
}
|
|
74
74
|
const sessionId = randomUUID();
|
|
75
75
|
const now = Date.now();
|
|
@@ -84,6 +84,7 @@ export class DebugSessionRegistry {
|
|
|
84
84
|
haltWaiters: [],
|
|
85
85
|
createdAt: now,
|
|
86
86
|
lastActivityAt: now,
|
|
87
|
+
resolution,
|
|
87
88
|
};
|
|
88
89
|
this.sessions.set(sessionId, entry);
|
|
89
90
|
return entry;
|
package/dist/tools/index.d.ts
CHANGED
package/dist/tools/index.js
CHANGED
package/dist/tools/mrt/index.js
CHANGED
|
@@ -127,6 +127,7 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
127
127
|
isGA: true,
|
|
128
128
|
// MRT operations use ApiKeyStrategy from MRT_API_KEY or ~/.mobify
|
|
129
129
|
requiresMrtAuth: true,
|
|
130
|
+
usesProjectContext: true,
|
|
130
131
|
inputSchema: {
|
|
131
132
|
buildDirectory: z
|
|
132
133
|
.string()
|
|
@@ -167,12 +168,17 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
167
168
|
// Get origin from --cloud-origin flag or mrtOrigin config (optional)
|
|
168
169
|
const origin = context.mrtConfig?.origin;
|
|
169
170
|
// Detect project type and get project-type-aware defaults
|
|
170
|
-
const
|
|
171
|
+
const projectDirectory = context.services.resolveProjectDirectory(args.projectDirectory);
|
|
172
|
+
const projectDir = projectDirectory.path;
|
|
171
173
|
const { projectTypes } = await detectWorkspaceTypeFn(projectDir);
|
|
172
174
|
const defaults = getDefaultsForProjectTypes(projectTypes);
|
|
173
175
|
const ssrOnly = args.ssrOnly ? parseGlobPatterns(args.ssrOnly) : defaults.ssrOnly;
|
|
174
176
|
const ssrShared = args.ssrShared ? parseGlobPatterns(args.ssrShared) : defaults.ssrShared;
|
|
175
|
-
const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory ?? defaults.buildDirectory);
|
|
177
|
+
const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory ?? defaults.buildDirectory, args.projectDirectory);
|
|
178
|
+
context.setResolvedDirectory('buildDirectory', {
|
|
179
|
+
path: buildDirectory,
|
|
180
|
+
source: args.buildDirectory ? 'argument' : 'projectDirectory',
|
|
181
|
+
});
|
|
176
182
|
// Log all computed variables before pushing bundle
|
|
177
183
|
const logger = getLogger();
|
|
178
184
|
logger.debug({
|
|
@@ -196,7 +202,11 @@ function createMrtBundlePushTool(loadServices, injections) {
|
|
|
196
202
|
target: environment,
|
|
197
203
|
origin, // MRT API origin URL (optional, defaults to https://cloud.mobify.com)
|
|
198
204
|
}, context.mrtConfig.auth);
|
|
199
|
-
return
|
|
205
|
+
return {
|
|
206
|
+
...result,
|
|
207
|
+
projectDirectory,
|
|
208
|
+
resolvedBuildDirectory: buildDirectory,
|
|
209
|
+
};
|
|
200
210
|
},
|
|
201
211
|
formatOutput: (output) => jsonResult(output),
|
|
202
212
|
}, loadServices);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z, type ZodRawShape } from 'zod';
|
|
2
|
+
/** Input shared by MCP tools that resolve files or configuration from a project. */
|
|
3
|
+
export interface ProjectContextInput {
|
|
4
|
+
/** Per-call project directory override. */
|
|
5
|
+
projectDirectory?: string;
|
|
6
|
+
/** Per-call explicit primary dw.json-format configuration path. */
|
|
7
|
+
configPath?: string;
|
|
8
|
+
/** Per-call named instance selection. */
|
|
9
|
+
instanceName?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Effective project directory and the source that selected it. */
|
|
12
|
+
export interface ProjectDirectoryInfo {
|
|
13
|
+
path: string;
|
|
14
|
+
source: 'argument' | 'config' | 'cwd';
|
|
15
|
+
}
|
|
16
|
+
/** How the selected dw.json file entered the configuration resolver. */
|
|
17
|
+
export type ConfigurationResolutionSource = 'argument' | 'globalDefault' | 'none' | 'projectDirectory' | 'projectEnvironment' | 'server';
|
|
18
|
+
/** Compact selected-configuration provenance returned by project-aware tools. */
|
|
19
|
+
export interface ConfigurationResolutionInfo {
|
|
20
|
+
hostname?: string;
|
|
21
|
+
instanceName?: string;
|
|
22
|
+
path?: string;
|
|
23
|
+
source: ConfigurationResolutionSource;
|
|
24
|
+
}
|
|
25
|
+
/** Provenance for a specialized project-relative directory. */
|
|
26
|
+
export interface DirectoryResolutionInfo {
|
|
27
|
+
path: string;
|
|
28
|
+
source: 'argument' | 'projectDirectory';
|
|
29
|
+
}
|
|
30
|
+
/** Compact, common provenance block returned by project/config-aware tools. */
|
|
31
|
+
export interface ToolResolution {
|
|
32
|
+
configuration?: ConfigurationResolutionInfo;
|
|
33
|
+
directories?: Record<string, DirectoryResolutionInfo>;
|
|
34
|
+
projectDirectory: ProjectDirectoryInfo;
|
|
35
|
+
}
|
|
36
|
+
/** Defaults known when MCP tool schemas are registered. */
|
|
37
|
+
export interface ProjectContextDefaults {
|
|
38
|
+
projectDirectory: ProjectDirectoryInfo;
|
|
39
|
+
}
|
|
40
|
+
/** Whether a tool needs only a project root or full configuration selection. */
|
|
41
|
+
export type ProjectContextKind = 'configuration' | 'project';
|
|
42
|
+
/** Build the canonical project-directory field with the effective fallback embedded in its description. */
|
|
43
|
+
export declare function createProjectDirectoryInput(defaults?: ProjectContextDefaults): z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
44
|
+
/** Build the canonical explicit primary dw.json field. */
|
|
45
|
+
export declare function createConfigPathInput(): z.ZodOptional<z.ZodString>;
|
|
46
|
+
/** Build the canonical named-instance selection field. */
|
|
47
|
+
export declare function createInstanceNameInput(): z.ZodOptional<z.ZodString>;
|
|
48
|
+
/** Build flat canonical schema fields for a local-project or configuration-aware tool. */
|
|
49
|
+
export declare function createProjectContextInputSchema(kind: ProjectContextKind, defaults?: ProjectContextDefaults): ZodRawShape;
|
|
50
|
+
/** Static field for schemas declared outside the shared adapter. */
|
|
51
|
+
export declare const projectDirectoryInput: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
52
|
+
/** Static configuration schema for legacy/manual tool definitions. */
|
|
53
|
+
export declare const projectContextInputSchema: z.ZodRawShape;
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
import path from 'node:path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
function defaultProjectContext() {
|
|
9
|
+
return { projectDirectory: { path: process.cwd(), source: 'cwd' } };
|
|
10
|
+
}
|
|
11
|
+
/** Build the canonical project-directory field with the effective fallback embedded in its description. */
|
|
12
|
+
export function createProjectDirectoryInput(defaults = defaultProjectContext()) {
|
|
13
|
+
const fallback = defaults.projectDirectory;
|
|
14
|
+
const sourceDescription = fallback.source === 'cwd'
|
|
15
|
+
? 'the MCP process working directory'
|
|
16
|
+
: 'the server-level --project-directory / SFCC_PROJECT_DIRECTORY value';
|
|
17
|
+
return z
|
|
18
|
+
.string()
|
|
19
|
+
.refine((value) => path.isAbsolute(value), 'projectDirectory must be an absolute path')
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(`Optional absolute project root for this call. Overrides the server-level project directory. ` +
|
|
22
|
+
`When omitted, uses ${sourceDescription}: ${fallback.path}`);
|
|
23
|
+
}
|
|
24
|
+
/** Build the canonical explicit primary dw.json field. */
|
|
25
|
+
export function createConfigPathInput() {
|
|
26
|
+
return z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Optional path to a dw.json-format configuration file. Relative paths resolve from projectDirectory. ' +
|
|
30
|
+
'Selects the primary file ahead of server and project automatic selection; the shared default dw.json remains available as a fallback and for named-instance lookup.');
|
|
31
|
+
}
|
|
32
|
+
/** Build the canonical named-instance selection field. */
|
|
33
|
+
export function createInstanceNameInput() {
|
|
34
|
+
return z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Optional named instance to select from the resolved primary and default dw.json files. The primary file is searched first. When omitted, the active/default instance is used.');
|
|
39
|
+
}
|
|
40
|
+
/** Build flat canonical schema fields for a local-project or configuration-aware tool. */
|
|
41
|
+
export function createProjectContextInputSchema(kind, defaults = defaultProjectContext()) {
|
|
42
|
+
const project = { projectDirectory: createProjectDirectoryInput(defaults) };
|
|
43
|
+
if (kind === 'project')
|
|
44
|
+
return project;
|
|
45
|
+
return {
|
|
46
|
+
...project,
|
|
47
|
+
configPath: createConfigPathInput(),
|
|
48
|
+
instanceName: createInstanceNameInput(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Static field for schemas declared outside the shared adapter. */
|
|
52
|
+
export const projectDirectoryInput = createProjectDirectoryInput();
|
|
53
|
+
/** Static configuration schema for legacy/manual tool definitions. */
|
|
54
|
+
export const projectContextInputSchema = createProjectContextInputSchema('configuration');
|
|
55
|
+
//# sourceMappingURL=project-context.js.map
|
|
@@ -63,6 +63,7 @@ Retrieve observability metrics time-series for a B2C Commerce tenant. Returns me
|
|
|
63
63
|
toolsets: ['SCAPI'],
|
|
64
64
|
isGA: false,
|
|
65
65
|
requiresInstance: false, // SCAPI uses OAuth directly
|
|
66
|
+
usesConfigurationContext: true,
|
|
66
67
|
inputSchema: {
|
|
67
68
|
category: z
|
|
68
69
|
.enum(['overall', 'sales', 'ecdn', 'third-party', 'scapi', 'scapi-hooks', 'mrt', 'controller', 'ocapi'])
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Services } from '../../services.js';
|
|
2
2
|
import type { McpTool } from '../../utils/index.js';
|
|
3
|
+
import type { ProjectContextInput, ProjectDirectoryInfo } from '../project-context.js';
|
|
3
4
|
import type { Scaffold, ResolvedParameters, ResolveParametersOptions } from '@salesforce/b2c-tooling-sdk/scaffold';
|
|
4
5
|
/** Optional overrides for testing (scaffold not found, missing required). */
|
|
5
6
|
export interface ScaffoldCustomApiExecuteOverrides {
|
|
@@ -12,7 +13,7 @@ export interface ScaffoldCustomApiExecuteOverrides {
|
|
|
12
13
|
* Input schema for scapi_custom_api_generate_scaffold tool.
|
|
13
14
|
* Parameters match the custom-api scaffold: apiName, apiType, cartridgeName, etc.
|
|
14
15
|
*/
|
|
15
|
-
interface ScaffoldCustomApiInput {
|
|
16
|
+
interface ScaffoldCustomApiInput extends ProjectContextInput {
|
|
16
17
|
/** API name (kebab-case, e.g. my-products). Required. */
|
|
17
18
|
apiName: string;
|
|
18
19
|
/** Cartridge name that will contain the API. Optional; defaults to first cartridge found in project. */
|
|
@@ -22,8 +23,12 @@ interface ScaffoldCustomApiInput {
|
|
|
22
23
|
/** Short description of the API. Default: "A custom B2C Commerce API" */
|
|
23
24
|
apiDescription?: string;
|
|
24
25
|
/** Project root for cartridge discovery and output. Default: MCP project directory */
|
|
26
|
+
cartridgeDirectory?: string;
|
|
27
|
+
/** @deprecated Use cartridgeDirectory. */
|
|
25
28
|
projectRoot?: string;
|
|
26
29
|
/** Output directory override. Default: scaffold default or project root */
|
|
30
|
+
outputDirectory?: string;
|
|
31
|
+
/** @deprecated Use outputDirectory. */
|
|
27
32
|
outputDir?: string;
|
|
28
33
|
}
|
|
29
34
|
/**
|
|
@@ -40,6 +45,8 @@ interface ScaffoldCustomApiOutput {
|
|
|
40
45
|
}>;
|
|
41
46
|
postInstructions?: string;
|
|
42
47
|
error?: string;
|
|
48
|
+
projectDirectory: ProjectDirectoryInfo;
|
|
49
|
+
projectRoot: string;
|
|
43
50
|
}
|
|
44
51
|
/**
|
|
45
52
|
* Core execute logic for the custom API scaffold tool.
|