Maximo Script Debugger
VS Code debug extension for Maximo automation scripts (Jython and Nashorn JS). The extension launches the Java Maximo-debugger DAP backend over stdio, and the backend attaches to a JDWP-enabled Maximo JVM.
Pre-release. This is an early (0.0.1) pre-release. It targets development/test Maximo environments. See Known Limitations and Security before using it.
Requirements
- VS Code 1.116 or newer.
- Java 17 or newer to run the debugger host process (the backend uses
jdk.jdi).
- Download a JDK from Eclipse Temurin: https://adoptium.net/temurin/releases/?version=17. Pick the JDK (not JRE) for your OS/arch, download the
.zip/.tar.gz, and extract it anywhere — no installer required. Then point the extension at it with mxscriptMaximoDebugger.javaHome (the extracted folder) or mxscriptMaximoDebugger.javaPath (the bin/java inside it). Run Maximo Debugger: Validate Java Runtime to confirm.
- A Maximo JVM started with JDWP enabled — see Enabling JDWP on Maximo.
- A runnable Maximo debugger backend jar at
server/maximo-debugger.jar (bundled), or an override path in debuggerJarPath / mxscriptMaximoDebugger.debuggerJarPath.
- (Recommended) the in-Maximo helper driver + agent deployed — see Deploying the helper driver + agent. Without it, Jython line breakpoints fall back to a slower, less precise mode.
Build and copy the standalone backend jar during local development:
cd ../Maximo-debugger
mvn package
cd ../mxscript-maximo-debugger
pnpm run copy-backend
If the backend jar lives somewhere else:
"mxscriptMaximoDebugger.debuggerJarPath": "C:/path/to/maximo-debugger.jar"
If you use a non-standalone backend jar, point the extension at a dependency directory too:
"mxscriptMaximoDebugger.debuggerLibPath": "C:/path/to/backend/lib"
Sample Attach Configuration
{
"type": "mxscript-maximo-debugger",
"request": "attach",
"name": "Attach to Maximo",
"host": "localhost",
"port": "7777",
"engineMode": "AUTO",
"scriptDiscoveryMethod": "rest-api",
"jythonPyxMappingMethod": "jdi-cache",
"helperScriptExecutor": "builtin-rest",
"jythonSourceRoots": ["${workspaceFolder}/scripts/jython"],
"nashornSourceRoots": ["${workspaceFolder}/scripts/nashorn"],
"sourceMappingMode": "hybrid",
"javaPath": "java",
"javaArgs": [],
"debuggerJarPath": "",
"debuggerLibPath": "",
"logLevel": "info",
"requireSourceMatch": false,
"attachTimeoutMillis": 30000,
"connectRetryCount": 0,
"connectRetryDelayMillis": 2000,
"suspendOnAttach": false,
"resumeOnDisconnect": true,
"enableLoadedSources": true,
"enableExceptionBreakpoints": false,
"enableVerboseJdiLogging": false,
"enableProtocolTracing": false,
"nashornVariableSummaryMode": "safeLazy"
}
Enabling JDWP on Maximo (MAS 9 & Maximo 7.6)
The extension attaches to the Maximo JVM over JDWP (the standard Java debug wire protocol). You enable it by adding one JVM argument and exposing the port. This brief follows the approach in Sharptree's "remote debugging Maximo automation scripts" guidance (https://sharptree.io); adapt it to your environment.
The JVM argument is the same on both versions:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:7777
server=y — the JVM listens; the debugger connects in.
suspend=n — the JVM does not wait for a debugger at startup.
address=*:7777 — listen on port 7777 on all interfaces (use a specific bind address if your platform requires it).
Maximo 7.6 (traditional WebSphere):
- WebSphere admin console → Servers → Server Types → WebSphere application servers →
<your MXServer> → Process definition → Java Virtual Machine.
- Add the
-agentlib:jdwp=... line above to Generic JVM arguments, save, and synchronize the node.
- Restart the MXServer JVM.
- Make sure port
7777 is reachable from your workstation (host firewall / network).
MAS 9 (containerized — OpenLiberty on OpenJ9 in OpenShift/Kubernetes):
- Add the
-agentlib:jdwp=... argument to the server's JVM options (e.g. a jvm.options entry or the JVM_ARGS/server-customization mechanism your MAS deployment uses).
- Roll/restart the Manage (
*-manage / *-wlp-*) pod so the JVM picks up the argument.
- Expose port
7777 from the pod — e.g. a Service/NodePort, an OpenShift Route (TCP), or oc port-forward svc/<manage-svc> 7777:7777 for a quick local session.
The bundled in-Maximo helper also exposes a runtime enableJdwp action that can load the JDWP agent into an already-running JVM without a restart, but loading the debug agent at runtime is environment-dependent and is not a substitute for the supported boot-argument approach above.
Deploying the helper driver + agent
For the most accurate Jython line breakpoints (agent-strict mode), deploy the in-Maximo helper driver + agent. It installs a DebugJSR223ScriptDriver and a PyxLineAgent that rewrites Jython's broken _pyx line tables so JDI line breakpoints land on the right line.
- From VS Code, run
Maximo Debugger: Deploy Helper Driver + Agent. Set mxscriptMaximoDebugger.helperDriverProjectPath to the maximo-debug-driver project folder if the extension can't locate it automatically.
- Or run
maximo-debug-driver/scripts/deploy.ps1 (Windows) / deploy.sh (POSIX), which build the jars and upload them over Maximo's REST API.
- The deploy is hot (no Maximo restart) and idempotent. After a Maximo restart you must redeploy the helper.
- Without the helper, the debugger still works but Jython breakpoints use a slower fallback and may bind less precisely. When attaching in
agent-strict mode without the agent present, the extension prompts you to deploy it.
Nashorn Variables
Nashorn variables are displayed in VS Code's normal Variables tree. safeLazy is the default mode: locals show cheap scalar summaries immediately, while objects, arrays, Java collections, maps, custom classes, globals, closures, and implicit runtime metadata are expanded only when you open that node in the tree.
The backend owns Nashorn value inspection and emits DAP type, variablesReference, and child count metadata so the extension does not need a custom reveal button or separate variable UI.
Commands
Maximo Debugger: Open Logs
Maximo Debugger: Copy Sample Launch Config
Maximo Debugger: Copy Launch Diagnostics
Maximo Debugger: Validate Java Runtime
Maximo Debugger: Refresh Scripts
Maximo Debugger: Stop Script Scan
Maximo Debugger: Show Recent Script Executions
Maximo Debugger: Deploy Helper Driver + Agent
Maximo Debugger: Pick Debug Script (Catalog)
Settings
mxscriptMaximoDebugger.javaPath: Java executable used to start the backend. Defaults to java.
mxscriptMaximoDebugger.debuggerJarPath: Optional backend jar override.
mxscriptMaximoDebugger.debuggerLibPath: Optional backend dependency jar directory.
mxscriptMaximoDebugger.logLevel: Backend log level.
mxscriptMaximoDebugger.traceAdapter: Show resolved backend command and verbose diagnostics.
The attach configuration also supports per-session overrides for javaPath, javaArgs, debuggerJarPath, debuggerLibPath, and logLevel.
Use Maximo Debugger: Copy Launch Diagnostics to copy the resolved workspace roots, backend paths, and computed Java command for the current default attach configuration.
Known Limitations
This is a pre-release. Be aware of the following before relying on it:
- Re-attach may hang the JVM's JDWP listener. On some JVMs (notably OpenJ9
with
server=y libjdwp), the JDWP server-side socket can wedge after a
couple of attach/detach cycles — a fresh attach then stalls or the port
becomes unreachable. The extension does its best to fully resume threads and
tear down its JDI event requests on disconnect, but if attaches start
failing, restart the Maximo JVM (the pod/server) to clear the stuck
listener. This is a JVM/JDWP behavior, not something the extension can fully
work around.
- Conditional breakpoints, hit-count breakpoints, and logpoints are
experimental on Jython. They are evaluated against the in-Maximo compiled
_pyx frame and can be intermittent — a condition that should pause may
occasionally not, or vice versa — because the expression evaluation shares
the same suspended-thread dispatch as the stop. Treat them as best-effort.
Plain (unconditional) line breakpoints are reliable. Nashorn conditions are
more stable than Jython.
- Helper redeploy after restart. The in-Maximo helper driver/agent is a
hot, non-persistent deploy. After any Maximo restart you must redeploy it.
- One JDWP debug session at a time per Maximo JVM is the supported mode.
Security
JDWP is a remote-code-execution channel. Enable it only on development and
test environments you control.
- An open JDWP port lets anyone who can reach it run arbitrary code inside
the Maximo JVM with full application privileges — there is no authentication
on the debug protocol.
- Never enable JDWP on a production Maximo, and never expose the JDWP port
to the public internet or an untrusted network. Bind it to localhost or a
private network and use a VPN / SSH tunnel /
oc port-forward to reach it.
- Remove the
-agentlib:jdwp=... JVM argument (and any exposed
port/route/service) when you are done debugging.
- The in-Maximo helper driver + agent execute with Maximo's privileges and can
rewrite loaded classes — deploy them only to environments you trust and
intend to debug.
Troubleshooting
- If attach fails before the backend starts, run
Maximo Debugger: Validate Java Runtime.
- If the backend jar is missing, build
Maximo-debugger and run pnpm run copy-backend, or set debuggerJarPath.
- If breakpoints stay unverified, check
jythonSourceRoots, nashornSourceRoots, and sourceMappingMode.
- If the target does not accept JDWP attach, confirm the Maximo JVM is listening on the configured host and port.