| description | DAP debug adapter, interactive REPL, and JSONL RPC mode for B2C Commerce server-side script debugging. |
|---|
Commands for connecting to the B2C Commerce Script Debugger API (SDAPI) to set breakpoints, inspect variables, and step through server-side code.
b2c debug— Debug Adapter Protocol (DAP) adapter for IDE integrations (VS Code, JetBrains, etc.).b2c debug cli— interactive terminal REPL, or JSONL-over-stdio RPC mode for headless scripts and agents.
The script debugger uses Basic auth (Business Manager username and password). OAuth credentials are not sufficient. Provide credentials via any of:
--username/--passwordflagsSFCC_USERNAME/SFCC_PASSWORDenvironment variablesusername/passwordfields indw.json
The script debugger must also be enabled on the instance: Business Manager > Administration > Development Configuration > Script Debugger > Enable.
See the Authentication Guide for details.
The b2c debug command launches a Debug Adapter Protocol (DAP) adapter that bridges your IDE to the B2C Commerce script debugger. It's designed to be invoked by an IDE over stdio, not run directly in a shell.
b2c debug [--cartridge-path <PATH>] [--client-id <ID>]| Flag | Description | Default |
|---|---|---|
--cartridge-path |
Path to your cartridges directory. The adapter recursively discovers cartridges under this path and maps them to the running instance. | . |
--client-id |
Client ID reported to the B2C script debugger API. Useful when multiple debug sessions share an instance. | b2c-cli |
Inherits the global instance and authentication flags (--server, --username, --password, etc.).
# Run from a project root with cartridges in ./cartridges or ./
b2c debug
# Point at an explicit cartridges directory
b2c debug --cartridge-path ./cartridges
# Use a non-default debugger client ID
b2c debug --client-id my-debuggerMost IDEs spawn DAP adapters automatically based on a launch configuration. The adapter speaks DAP over stdin/stdout, so direct shell invocation will appear to hang — that's expected. Configure your IDE's debug launcher to invoke b2c debug and supply the appropriate environment.
- A warning is emitted if no cartridges are found at
--cartridge-path. - Source maps are derived from the discovered cartridge layout; ensure your local cartridge tree matches what's deployed to the instance, otherwise breakpoints may not bind.
- The adapter exits when its stdin stream closes.
Start an interactive CLI debug session with a REPL interface. Provides a terminal-based debugging experience without requiring a DAP client. Add --rpc to switch to JSONL-over-stdio mode for headless scripts and agents.
b2c debug cli [--cartridge-path <PATH>] [--client-id <ID>] [--rpc]| Flag | Description | Default |
|---|---|---|
--cartridge-path |
Path to directory containing cartridges | . |
--client-id |
Client ID for the debugger API | b2c-cli |
--rpc |
Run in RPC mode (JSONL over stdin/stdout) | false |
Inherits the global instance and authentication flags.
| Command | Alias | Description |
|---|---|---|
break <file>:<line> [if <cond>] |
b |
Set breakpoint |
breakpoints |
bl |
List active breakpoints |
delete <id> |
d |
Delete breakpoint |
continue |
c |
Resume current thread |
step |
s |
Step over |
stepin |
si |
Step into |
stepout |
so |
Step out |
stack |
bt |
Show call stack |
frame <n> |
f |
Select stack frame |
vars |
v |
Show variables in current frame |
members <path> |
m |
Expand object members |
eval <expr> |
e |
Evaluate expression |
threads |
t |
List known threads |
thread <id> |
Switch to thread | |
help |
h |
Show commands |
quit |
q |
Disconnect and exit |
# Start interactive debugger
b2c debug cli
# Specify cartridge directory
b2c debug cli --cartridge-path ./cartridges
# Use a custom client ID (for concurrent sessions)
b2c debug cli --client-id my-session
# Start in RPC mode for headless scripts
b2c debug cli --rpcdebug> break Cart.js:42
Breakpoint #1 set at ./cartridges/app_storefront/cartridge/controllers/Cart.js:42
debug> break Checkout.js:100 if basket.totalGrossPrice > 100
Breakpoint #2 set at ./cartridges/app_storefront/cartridge/controllers/Checkout.js:100
● Thread 5 halted at ./cartridges/app_storefront/cartridge/controllers/Cart.js:42 in show()
debug> vars
request: dw.system.Request = [object Request] [local]
basket: dw.order.Basket = [object Basket] [local]
debug> eval basket.productLineItems.length
3
debug> stack
→ #0 show ./cartridges/app_storefront/cartridge/controllers/Cart.js:42
#1 execute /app_storefront/cartridge/controllers/Cart.js:1
debug> continue
Thread 5 resumed.
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.
- Input (stdin): One JSON object per line (JSONL)
- Output (stdout): One JSON object per line — either a response or an async event
{"id": 1, "command": "set_breakpoints", "args": {"breakpoints": [{"file": "Cart.js", "line": 42}]}}| Field | Type | Description |
|---|---|---|
id |
number or string | Optional. Echoed back in the response for correlation. |
command |
string | Required. The command to execute. |
args |
object | Optional. Command-specific arguments. |
{"id": 1, "result": {"breakpoints": [{"id": 1, "file": "Cart.js", "line": 42, "script_path": "/app_storefront/cartridge/controllers/Cart.js"}]}}On error:
{"id": 1, "error": "No thread selected. Wait for a thread_stopped event."}Events are emitted asynchronously (not in response to a command):
{"event": "ready", "data": {}}
{"event": "thread_stopped", "data": {"thread_id": 5, "location": {"file": "Cart.js", "line": 42, "function_name": "show", "script_path": "/app_storefront/cartridge/controllers/Cart.js"}}}| Command | Args | Description |
|---|---|---|
set_breakpoints |
breakpoints: [{file, line, condition?}] |
Replace all breakpoints |
list_breakpoints |
List current breakpoints | |
continue |
thread_id? |
Resume a halted thread |
step_over |
thread_id? |
Step to next line |
step_into |
thread_id? |
Step into function call |
step_out |
thread_id? |
Step out of function |
get_stack |
thread_id? |
Get call stack frames |
get_variables |
thread_id?, frame_index?, scope?, object_path? |
Get variables |
evaluate |
expression, thread_id?, frame_index? |
Evaluate expression |
list_threads |
List known threads | |
select_thread |
thread_id |
Switch current thread |
select_frame |
index |
Switch current frame |
When thread_id is omitted, the last thread that halted is used.
| Event | Description |
|---|---|
ready |
Emitted once after connection is established |
thread_stopped |
A thread hit a breakpoint or step completed |
import subprocess, json
proc = subprocess.Popen(
["b2c", "debug", "cli", "--rpc"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
text=True, bufsize=1
)
def send(cmd, args=None, id=None):
msg = {"command": cmd}
if args: msg["args"] = args
if id is not None: msg["id"] = id
proc.stdin.write(json.dumps(msg) + "\n")
proc.stdin.flush()
def recv():
return json.loads(proc.stdout.readline())
# Wait for ready
assert recv()["event"] == "ready"
# Set a breakpoint
send("set_breakpoints", {"breakpoints": [{"file": "Cart.js", "line": 42}]}, id=1)
response = recv() # {"id": 1, "result": {...}}
# Wait for breakpoint hit (trigger a request on the instance)
event = recv() # {"event": "thread_stopped", "data": {...}}
# Inspect state
send("get_stack", id=2)
stack = recv()
send("get_variables", id=3)
variables = recv()
# Continue execution
send("continue", id=4)
recv()- Authentication Guide — Setting up instance credentials
- Logs Commands — Retrieving server logs for debugging
- Code Commands — Deploying code before debugging