Skip to content

Commit f357bf9

Browse files
committed
Add script debugger support to MCP tools, CLI, and docs
- Add 13 MCP debug tools (debug_start_session, debug_set_breakpoints, debug_wait_for_stop, debug_get_stack, debug_get_variables, debug_evaluate, debug_continue, debug_step_over/into/out, debug_end_session, debug_list_sessions, debug_capture_at_breakpoint) to CARTRIDGES, SCAPI, and STOREFRONTNEXT toolsets - Add ServerContext for persistent server-scoped state across MCP tool invocations (debug sessions, future log watches) - Add DebugSessionRegistry with TTL cleanup and multi-session support - Add `b2c debug cli` command with interactive REPL and --rpc mode for JSONL-over-stdio headless/agent integration - Add resolveBreakpointPath utility in SDK for flexible path normalization (server paths, local paths, cartridge-prefixed paths) - Add debug command docs and b2c-debug agent skill
1 parent 51aed02 commit f357bf9

33 files changed

Lines changed: 2585 additions & 8 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-cli': minor
3+
---
4+
5+
Add `b2c debug cli` command for interactive terminal-based script debugging. Includes a REPL with commands for breakpoints, stepping, variable inspection, and expression evaluation. Use `--rpc` for JSONL-over-stdio mode suitable for headless scripts and agents.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-dx-mcp': minor
3+
---
4+
5+
Add script debugger MCP tools to the CARTRIDGES and STOREFRONTNEXT toolsets. Includes `debug_start_session`, `debug_end_session`, `debug_list_sessions`, `debug_set_breakpoints`, `debug_wait_for_stop`, `debug_get_stack`, `debug_get_variables`, `debug_evaluate`, `debug_continue`, `debug_step_over`, `debug_step_into`, `debug_step_out`, and `debug_capture_at_breakpoint`.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@salesforce/b2c-dx-docs': patch
3+
'@salesforce/b2c-agent-plugins': patch
4+
---
5+
6+
Add debug command documentation and b2c-debug agent skill covering interactive REPL, RPC mode, and DAP usage.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-dx-mcp': minor
3+
---
4+
5+
Add `ServerContext` for persistent server-scoped state across MCP tool invocations. Enables stateful tools (debug sessions, log watches) while preserving per-call config reloading for existing tools.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-tooling-sdk': minor
3+
---
4+
5+
Add `resolveBreakpointPath` utility that normalizes user-provided file paths to SDAPI script paths. Accepts server paths, absolute/relative local paths, and cartridge-name-prefixed paths with helpful error messages on failure.

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ const referenceSidebar = [
106106
{text: 'CIP', link: '/cli/cip'},
107107
{text: 'CAP (Commerce Apps)', link: '/cli/cap'},
108108
{text: 'Code', link: '/cli/code'},
109+
{text: 'Debug', link: '/cli/debug'},
109110
{text: 'Content', link: '/cli/content'},
110111
{text: 'Custom APIs', link: '/cli/custom-apis'},
111112
{text: 'Docs', link: '/cli/docs'},

docs/cli/debug.md

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
---
2+
description: Commands for interactive script debugging on B2C Commerce instances.
3+
---
4+
5+
# Debug Commands
6+
7+
Commands for connecting to the B2C Commerce Script Debugger API (SDAPI) to set breakpoints, inspect variables, and step through server-side code.
8+
9+
## Authentication
10+
11+
All debug commands require **Basic Auth** credentials (username and password) for a Business Manager user with the `WebDAV_Manage_Customization` permission. See [Configuration](/guide/configuration) for details on setting credentials via flags, environment variables, or dw.json.
12+
13+
The script debugger must also be enabled on the instance: Business Manager > Administration > Development Configuration > Script Debugger > Enable.
14+
15+
---
16+
17+
## b2c debug
18+
19+
Start a DAP (Debug Adapter Protocol) debug adapter over stdio. This is used by IDE integrations (VS Code, JetBrains) that speak DAP natively.
20+
21+
### Usage
22+
23+
```bash
24+
b2c debug
25+
```
26+
27+
### Flags
28+
29+
| Flag | Description | Default |
30+
|------|-------------|---------|
31+
| `--cartridge-path` | Path to directory containing cartridges | `.` |
32+
| `--client-id` | Client ID for the debugger API | `b2c-cli` |
33+
34+
See [Global Flags](/cli/#global-flags) for authentication and instance flags.
35+
36+
### Examples
37+
38+
```bash
39+
# Start DAP adapter (used by VS Code launch configuration)
40+
b2c debug
41+
42+
# Specify cartridge directory
43+
b2c debug --cartridge-path ./cartridges
44+
```
45+
46+
---
47+
48+
## b2c debug cli
49+
50+
Start an interactive CLI debug session with a REPL interface. Provides a terminal-based debugging experience without requiring a DAP client.
51+
52+
### Usage
53+
54+
```bash
55+
b2c debug cli
56+
```
57+
58+
### Flags
59+
60+
| Flag | Description | Default |
61+
|------|-------------|---------|
62+
| `--cartridge-path` | Path to directory containing cartridges | `.` |
63+
| `--client-id` | Client ID for the debugger API | `b2c-cli` |
64+
| `--rpc` | Run in RPC mode (JSONL over stdin/stdout) | `false` |
65+
66+
See [Global Flags](/cli/#global-flags) for authentication and instance flags.
67+
68+
### REPL Commands
69+
70+
| Command | Alias | Description |
71+
|---------|-------|-------------|
72+
| `break <file>:<line> [if <cond>]` | `b` | Set breakpoint |
73+
| `breakpoints` | `bl` | List active breakpoints |
74+
| `delete <id>` | `d` | Delete breakpoint |
75+
| `continue` | `c` | Resume current thread |
76+
| `step` | `s` | Step over |
77+
| `stepin` | `si` | Step into |
78+
| `stepout` | `so` | Step out |
79+
| `stack` | `bt` | Show call stack |
80+
| `frame <n>` | `f` | Select stack frame |
81+
| `vars` | `v` | Show variables in current frame |
82+
| `members <path>` | `m` | Expand object members |
83+
| `eval <expr>` | `e` | Evaluate expression |
84+
| `threads` | `t` | List known threads |
85+
| `thread <id>` | | Switch to thread |
86+
| `help` | `h` | Show commands |
87+
| `quit` | `q` | Disconnect and exit |
88+
89+
### Examples
90+
91+
```bash
92+
# Start interactive debugger
93+
b2c debug cli
94+
95+
# Specify cartridge directory
96+
b2c debug cli --cartridge-path ./cartridges
97+
98+
# Use a custom client ID (for concurrent sessions)
99+
b2c debug cli --client-id my-session
100+
101+
# Start in RPC mode for headless scripts
102+
b2c debug cli --rpc
103+
```
104+
105+
### Interactive Session Example
106+
107+
```
108+
debug> break Cart.js:42
109+
Breakpoint #1 set at ./cartridges/app_storefront/cartridge/controllers/Cart.js:42
110+
111+
debug> break Checkout.js:100 if basket.totalGrossPrice > 100
112+
Breakpoint #2 set at ./cartridges/app_storefront/cartridge/controllers/Checkout.js:100
113+
114+
● Thread 5 halted at ./cartridges/app_storefront/cartridge/controllers/Cart.js:42 in show()
115+
116+
debug> vars
117+
request: dw.system.Request = [object Request] [local]
118+
basket: dw.order.Basket = [object Basket] [local]
119+
120+
debug> eval basket.productLineItems.length
121+
3
122+
123+
debug> stack
124+
→ #0 show ./cartridges/app_storefront/cartridge/controllers/Cart.js:42
125+
#1 execute /app_storefront/cartridge/controllers/Cart.js:1
126+
127+
debug> continue
128+
Thread 5 resumed.
129+
```
130+
131+
---
132+
133+
## RPC Mode
134+
135+
When started with `--rpc`, the debug CLI runs as a JSONL-over-stdio RPC server. This enables headless scripts, agents, and other tools to drive the debugger programmatically.
136+
137+
### Protocol
138+
139+
- **Input** (stdin): One JSON object per line (JSONL)
140+
- **Output** (stdout): One JSON object per line — either a response or an async event
141+
142+
### Request Format
143+
144+
```json
145+
{"id": 1, "command": "set_breakpoints", "args": {"breakpoints": [{"file": "Cart.js", "line": 42}]}}
146+
```
147+
148+
| Field | Type | Description |
149+
|-------|------|-------------|
150+
| `id` | number or string | Optional. Echoed back in the response for correlation. |
151+
| `command` | string | Required. The command to execute. |
152+
| `args` | object | Optional. Command-specific arguments. |
153+
154+
### Response Format
155+
156+
```json
157+
{"id": 1, "result": {"breakpoints": [{"id": 1, "file": "Cart.js", "line": 42, "script_path": "/app_storefront/cartridge/controllers/Cart.js"}]}}
158+
```
159+
160+
On error:
161+
162+
```json
163+
{"id": 1, "error": "No thread selected. Wait for a thread_stopped event."}
164+
```
165+
166+
### Event Format
167+
168+
Events are emitted asynchronously (not in response to a command):
169+
170+
```json
171+
{"event": "ready", "data": {}}
172+
{"event": "thread_stopped", "data": {"thread_id": 5, "location": {"file": "Cart.js", "line": 42, "function_name": "show", "script_path": "/app_storefront/cartridge/controllers/Cart.js"}}}
173+
```
174+
175+
### Available Commands
176+
177+
| Command | Args | Description |
178+
|---------|------|-------------|
179+
| `set_breakpoints` | `breakpoints: [{file, line, condition?}]` | Replace all breakpoints |
180+
| `list_breakpoints` | | List current breakpoints |
181+
| `continue` | `thread_id?` | Resume a halted thread |
182+
| `step_over` | `thread_id?` | Step to next line |
183+
| `step_into` | `thread_id?` | Step into function call |
184+
| `step_out` | `thread_id?` | Step out of function |
185+
| `get_stack` | `thread_id?` | Get call stack frames |
186+
| `get_variables` | `thread_id?, frame_index?, scope?, object_path?` | Get variables |
187+
| `evaluate` | `expression, thread_id?, frame_index?` | Evaluate expression |
188+
| `list_threads` | | List known threads |
189+
| `select_thread` | `thread_id` | Switch current thread |
190+
| `select_frame` | `index` | Switch current frame |
191+
192+
When `thread_id` is omitted, the last thread that halted is used.
193+
194+
### Events
195+
196+
| Event | Description |
197+
|-------|-------------|
198+
| `ready` | Emitted once after connection is established |
199+
| `thread_stopped` | A thread hit a breakpoint or step completed |
200+
201+
### Example Session (Python)
202+
203+
```python
204+
import subprocess, json
205+
206+
proc = subprocess.Popen(
207+
["b2c", "debug", "cli", "--rpc"],
208+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
209+
text=True, bufsize=1
210+
)
211+
212+
def send(cmd, args=None, id=None):
213+
msg = {"command": cmd}
214+
if args: msg["args"] = args
215+
if id is not None: msg["id"] = id
216+
proc.stdin.write(json.dumps(msg) + "\n")
217+
proc.stdin.flush()
218+
219+
def recv():
220+
return json.loads(proc.stdout.readline())
221+
222+
# Wait for ready
223+
assert recv()["event"] == "ready"
224+
225+
# Set a breakpoint
226+
send("set_breakpoints", {"breakpoints": [{"file": "Cart.js", "line": 42}]}, id=1)
227+
response = recv() # {"id": 1, "result": {...}}
228+
229+
# Wait for breakpoint hit (trigger a request on the instance)
230+
event = recv() # {"event": "thread_stopped", "data": {...}}
231+
232+
# Inspect state
233+
send("get_stack", id=2)
234+
stack = recv()
235+
236+
send("get_variables", id=3)
237+
variables = recv()
238+
239+
# Continue execution
240+
send("continue", id=4)
241+
recv()
242+
```
243+
244+
---
245+
246+
## See Also
247+
248+
- [Configuration](/guide/configuration) - Setting up instance credentials
249+
- [Logs Commands](/cli/logs) - Retrieving server logs for debugging
250+
- [Code Commands](/cli/code) - Deploying code before debugging

0 commit comments

Comments
 (0)