@saptools/cf-function-trace
Records how one JavaScript function's state changes, step by step, in a Node.jsNode.jsA cross-platform JavaScript runtime that servers, command line tools and scripts written in JavaScript are run with. For the things here, the prerequisite a repository names when its build is a set of npm scripts. process running locally or on SAP BTP Cloud Foundry, and stores the run as a redacted timeline that can be queried later.
Takes one loaded file and one function selector, such as OrderService.create, and answers what that function did to its own state on a running service. record reads the source V8 has loaded through @saptools/cf-inspector@saptools/cf-inspectorSets breakpoints, captures variable snapshots and evaluates expressions on a remote Node.js process over the Chrome DevTools Protocol from the shell, with no IDE attached.independent, btp, arms one breakpoint, steps through the function and stores a full first state followed by JSON Pointer patches under ~/.saptools/cf-function-trace/, where show, state and diff read it without reconnecting. Sensitive keys, credential-shaped strings and email addresses are redacted before anything is written, and a remote run needs --confirm-impact because the Node.jsNode.jsA cross-platform JavaScript runtime that servers, command line tools and scripts written in JavaScript are run with. For the things here, the prerequisite a repository names when its build is a set of npm scripts. process is paused while state is captured. On Cloud FoundrySAP BTP, Cloud Foundry RuntimeThe Cloud Foundry runtime of SAP BTP: memory for applications in a Cloud Foundry org, run from SAP's Java, Node.js and Python buildpacks or community buildpacks and managed with the standard Cloud Foundry tools.sap official, btp it never enables SSH or restarts the app. Version 0.2.x traces one activation in one isolate; asynchronous child calls, several workers at once and mapping through source maps are outside it.
Facts
Where it sits
Who is behind it
In the atlas: maintains 18, contributes to 18@dongitranmaintainer
What it declares
Every artifact
- Type
- CLI
- Origin
- Independently maintained
- Runs on
- Cloud Foundry
As a CLI
- Distributed through
- npm
Connections
Seeing what running code did between input and result
Shell debugger for remote Node.js over the Chrome DevTools Protocol
A cross-platform JavaScript runtime that servers, command line tools and scripts written in JavaScript are run with. For the things here, the prerequisite a repository names when its build is a set of npm scripts.
Download
Install
npm add @saptools/cf-function-traceDerived from the package name. No recipe recorded; the README has the configuration.
Architecture
Download
README
quoted from dongitran/saptools under MIT, read@saptools/cf-function-trace
cf-function-trace turns one loaded JavaScript file plus one function selector into a bounded,
redacted runtime timeline. It connects through @saptools/cf-inspector, resolves the exact source
currently loaded by V8, arms one exact breakpoint, steps through the selected function, and stores
an initial full state followed by replayable state patches.
The default store is private local state under:
~/.saptools/cf-function-trace/data/t<16-hex>/
This package is designed for AI agents and terminal automation: command output is compact JSON, the breakpoint-ready signal is machine readable, and saved runs can be queried without reconnecting to Cloud Foundry.
Installation
Install the CLI from npm:
npm install --global @saptools/cf-function-trace
cf-function-trace --help
For repository development, build and run the workspace package directly:
pnpm install
pnpm --filter @saptools/cf-function-trace... build
node packages/cf-function-trace/dist/cli.js --help
Node.js 20 or newer is required. For a Cloud Foundry target, the cf CLI must already be installed
and authenticated, and SSH must be enabled for the app and space.
The tracer uses an ownership-only tunnel and passes allowSshEnableRestart: false to
cf-debugger. If SSH is disabled, plan and record fail without enabling SSH or restarting the
application and return the stable code SSH_NOT_ENABLED. Enabling SSH and restarting an app remain
explicit operator actions outside this CLI.
The published package requires @saptools/cf-inspector@^0.6.0, which in turn resolves a compatible
@saptools/cf-debugger. CI installs the function-trace tarball by itself in a clean project so this
registry dependency chain is verified without workspace links.
Updates
Every command first checks npm for a newer @saptools/cf-function-trace (at most once an hour, one small request
with a 2-second timeout) and, when one exists, installs that exact version with the package manager
that owns the running binary and re-runs the command you typed on the new version. Both steps are
announced on stderr; nothing is printed when the install is already current:
cf-function-trace: updating 0.3.0 -> 0.4.0 ...
cf-function-trace: updated to 0.4.0; re-running the command
If the install cannot complete, one stderr line gives the manual command and the command runs on the
installed version; that version is not retried for a day. cf-function-trace self-update forces the check and
install now; cf-function-trace self-update --check only reports.
| Control | Effect |
|---|---|
SAPTOOLS_AUTO_UPDATE=on|notify|off | on (default) installs and re-runs; notify prints the manual command once per version; off never checks. Applies to every @saptools CLI. |
CF_FUNCTION_TRACE_AUTO_UPDATE | same values, this CLI only; wins over the global variable |
SAPTOOLS_UPDATE_INTERVAL_MINUTES | minutes between checks (default 60; 0 checks on every run) |
SAPTOOLS_NPM_REGISTRY | registry to check and install from (default: npm's configured registry, then npmjs) |
SAPTOOLS_UPDATE_DEBUG=1 | explain on stderr why nothing happened |
The updater switches itself off in CI (CI set), under NODE_ENV=test or NO_UPDATE_NOTIFIER, when
the binary runs from a source checkout, an npm link or an npx cache, and inside the re-run itself.
It never writes to stdout, never asks for input, never uses sudo, and never moves onto a prerelease.
Its state lives in ~/.saptools/updates/.
Quick start
First start record. It writes {"event":"breakpoint-armed"} to stderr only after the exact
breakpoint is active. Trigger the application request that invokes the function after receiving that
event; the CLI then writes its final run summary to stdout.
Local inspector:
cf-function-trace plan file:///srv/app/dist/orders.js OrderService.create \
--port 9229 --call-depth 0
cf-function-trace record file:///srv/app/dist/orders.js OrderService.create \
--port 9229 --call-depth 0
SAP BTP Cloud Foundry:
cf-function-trace record file:///home/vcap/app/dist/orders.js OrderService.create \
--region eu10 \
--org my-org \
--space dev \
--app orders-srv \
--process web \
--instance 0 \
--tunnel-port 24321 \
--confirm-impact
Remote tracing pauses the selected Node.js process while state is captured. The command therefore
requires --confirm-impact — plan included, even though plan itself never pauses anything, since
opening the remote tunnel at all requires the same confirmation. When an app instance runs more than
one Node.js process (for example a
npm start launcher alongside the app server), the tunnel auto-selects the process that owns the
app's $PORT listening socket — the HTTP server — so --node-pid is usually unnecessary. Pass
--node-pid <pid> only to override that choice, or when no single Node process listens on $PORT
(in which case selection stays ambiguous and fails closed). --tunnel-port is optional and selects a
preferred local CF SSH-forwarding port; omit it to keep cf-debugger's normal automatic allocation.
Non-interactive recording
record writes {"event":"breakpoint-armed"} to stderr the instant the entry breakpoint is live,
then blocks on stdout until the traced function actually returns (or a limit ends the run). An agent
or script cannot run it in the foreground and then trigger the request afterward — it must arm
record in the background, wait for that stderr line, trigger the request, and only then collect the
result:
# 1. Start record in the background; redirect stdout (final summary) and
# stderr (the armed signal) to files.
cf-function-trace record file:///home/vcap/app/dist/orders.js OrderService.create \
--app orders-srv --region eu10 --org my-org --space dev \
--confirm-impact --call-depth 0 \
>/tmp/cf-trace.out 2>/tmp/cf-trace.err &
disown
# 2. Wait for the armed signal. Poll the file itself so this still works even
# if the next step runs as a separate shell invocation.
until grep -q '"event":"breakpoint-armed"' /tmp/cf-trace.err 2>/dev/null; do
sleep 0.5
done
# 3. Trigger the real request now that the breakpoint is live.
curl -s -X POST https://orders-srv.example.com/orders -d '{"tempID":"abc"}'
# 4. Wait for record to finish -- its stdout file goes from empty to one JSON line.
until [ -s /tmp/cf-trace.out ]; do
sleep 0.5
done
RUN_ID=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("/tmp/cf-trace.out","utf8")).runId)')
# 5. Collect.
cf-function-trace show "$RUN_ID" --changes-only
If every step above runs inside one shell invocation, ordinary job control also works
(RECORD_PID=$! then wait "$RECORD_PID"). Prefer the file-polling form when steps run as separate
tool calls or a fresh shell each time: job control does not survive that, but the redirected files do.
plan never needs this recipe — it resolves the same file/selector pair and exits immediately without
arming a breakpoint.
Stopping a backgrounded record
Stop a backgrounded record with SIGTERM, never SIGKILL:
kill -TERM "$RECORD_PID"
# never: kill -9 / kill -KILL
record installs a process-wide guard so SIGINT, SIGTERM, an uncaught exception, or an unhandled
rejection all resume the paused application and close the owned SSH tunnel before the process exits.
SIGTERM gets a graceful window first; a second signal, or a fatal error, escalates straight to that
same guarded cleanup. SIGKILL cannot be caught by any process, so none of this runs: a SIGKILL'd
record can leave the target app paused at the breakpoint and its cf ssh tunnel orphaned
(the child process outlives the killed parent and keeps the local port and SSH session open),
freezing the app until that tunnel is cleared.
If a SIGKILL already happened, the tunnel is registered in the same session store cf-debugger
itself uses: run cf-debugger list to confirm the orphaned session, then cf-debugger stop <app> to
terminate it safely. If ownership cannot be verified, run cf-debugger doctor for the recorded PID,
port, and recovery reason. cf-debugger stop <app> --force can then remove the unrecoverable record
without signalling an unverified process. A tunnel left behind after that must be handled manually
only after independently confirming that the reported PID is the exact cf ssh process owning the
reported port; never kill a process merely because it matches a name or occupies the port.
Query a saved run
cf-function-trace show latest --changes-only --from 0 --limit 100
cf-function-trace state latest --at 17 --path /frames/0
cf-function-trace diff latest --from 9 --to 17 --path /frames/0
cf-function-trace runs --limit 20
cf-function-trace purge t0123456789abcdef
show gives a byte-bounded event page with hasMore and nextSeq; pass nextSeq back through
--from to continue without loading the full timeline. state requires an exact event sequence,
then verifies event kind, artifact kind, replay chain, and state hash. diff compares any two exact
reconstructed states. purge accepts only a complete validated run ID.
Output kinds
Event kind: baseline (first pause, full state), pause (a later step), exception (an exception
pause), completed (normal terminal event), truncated (terminal event when a limit such as
--max-steps cut the run short).
Event artifactKind: full (a complete state snapshot backs this event), patch (a JSON Pointer
diff from the previous state backs it), unchanged (state hash identical to the previous event).
Per-node/frame completeness: complete, truncated (a limit cut it off), unavailable (not
captured — a getter, or an internal-slot value such as a Map/Promise/Proxy), error (capturing
it failed).
Tagged non-JSON values carry their own kind: undefined, bigint, special-number
(NaN/Infinity), symbol, accessor (getter/setter, never invoked), unavailable, ref (a
back-reference to an already-captured node — cycles and aliases), redacted (a sensitive key or a
matched string such as an email address).
Truncated output
show degrades event detail before ever dropping an event outright: it caps each event's
changedPaths list first, then drops to a compact per-event form (function name/depth/line/column,
no stateHash), then shrinks the page itself — so a run's terminal event is the last thing to
disappear under a tight --max-output-bytes, never the first.
state and diff each hold one arbitrary JSON payload, not a list, so neither can shrink piece by
piece. An over-budget response instead degrades to the request envelope (runId/seq or
runId/from/to, plus path if one was given) with truncated: true, originalBytes, and a
hint string describing exactly how to get a response that fits — never a bare, content-free stub.
For example:
{"runId":"t0123456789abcdef","seq":11,"truncated":true,"originalBytes":124637,"hint":"Exceeds --max-output-bytes=300; narrow with --path, or raise --max-output-bytes to see the full result."}
To see the data: narrow with --path <json-pointer>, or raise --max-output-bytes (default
24000, maximum 1000000).
Trace semantics
--call-depth 0captures only the selected function.--call-depth 1or2can follow synchronous child calls whose loaded files are inside the runtime app root.- Node internals and files below
node_modulesare stepped out of and never captured. - Async functions and functions containing
awaitare traced with V8's async-aware stepping: the step loop stays bound to the one selected activation across eachawait. Between step boundaries the isolate runs (so the awaited I/O settles) rather than staying frozen, and unrelated pauses that occur during that window are released and skipped. Give a busy target--matchto pin the exact activation (see below).--max-paused-msstill bounds only real paused time, so raise--timeoutwhen the traced function awaits slow I/O. - The function selector must be unique. Supported selectors include declarations, arrow/function
expressions, class methods (including decorator-compiled class expressions such as
let X = class X {...}), constructors, accessors, object methods, and simple assigned methods. - Exact loaded URLs and absolute paths are preferred. A relative path is accepted only when it has one unique suffix match below the verified app root.
recordselects the first function entry hit afterbreakpoint-armed. Pass--match <expr>to arm a conditional entry breakpoint so only an activation whose entry frame satisfies the JavaScript expression is traced — for example--match 'req.data.tempID === "abc"'. V8 evaluates the condition in-process, so concurrent activations that do not match never pause the target. Without--match, production callers should quiesce unrelated traffic because the first hit cannot otherwise be proven to be the intended request.
The implementation reads source with the Chrome DevTools Protocol rather than depending on
cf-explorer: inspector source is the exact code V8 is executing. cf-explorer remains useful for
human discovery and is a possible future source-map fallback, but it is not required for a trace.
Storage and diff model
The first pause is a full redacted state. Changed pauses use deterministic JSON Pointer patches;
arrays are compared by stable prefix/suffix and index so one local-variable change does not replace
the whole frame list. New variables and frames use full add values. Unchanged pauses retain a
small event referencing the same state hash. A full checkpoint is written periodically and at a
normal trace end. The terminal event is named completed: its state is the last confirmed pause,
not a newly captured JavaScript return value.
data/t<run-id>/
manifest.json
events/000000.json
events/000001.json
states/000000.full.json
states/000001.patch.json
Directories use mode 0700, files use 0600, and writes are atomic. Runs expire after 24 hours by
default, each run is capped at 64 MiB, and the store keeps at most 100 runs unless the library API
configures retentionMs, maxRunBytes, or maxRuns differently. Expired runs are pruned when a
new run or an offline query command starts; there is no background deletion daemon. Event and state
sequence files are append-only, and readers cross-check every event/artifact pair before replay.
The manifest includes sourceHash, a SHA-256 digest of the exact source returned by V8, so a saved
run can be distinguished from the same URL after another deployment.
Safety limits
Important bounds have conservative defaults and strict upper limits:
--timeout <seconds>
--max-steps <count>
--max-paused-ms <milliseconds>
--checkpoint-every <count>
--max-object-depth <depth>
--max-root-vars <count>
--max-properties <count>
--max-nodes <count>
--max-state-bytes <bytes>
--async-stack-depth <count>
--match <expr> scopes the trace to one activation (see Trace semantics). --async-stack-depth
sets the async call-stack depth requested for async traces so resumed frames carry async stack
context; it is reset when the trace ends. --max-root-vars bounds how many top-level
locals/this/return a frame may show at all; --max-properties separately bounds how many
properties an individual captured object may show (its fan-out), so raising visibility into a
function's own scope does not also fatten every nested object.
Capture reads property descriptors without invoking getters. Cycles and aliases become graph
references; accessors, special numbers, bigint, unavailable values, and truncated values use tagged
records. Maps, sets, promises, dates, proxies, and other internal-slot values are explicitly marked
truncated or unavailable rather than falsely reported as complete. A captured function value's
description is hard-capped in length regardless of the remaining byte budget, since V8 reports a
function's full source text there. Sensitive keys, common authorization/token/certificate/credential
string forms, and email addresses are redacted before hashing, diffing, temporary writes, persistent
writes, or process output; set CF_FUNCTION_TRACE_SENSITIVE_KEYS (comma-separated key names) to
redact additional project-specific PII fields. There is deliberately no raw-data switch.
Capture, persistence, and stepping are watchdog-bounded by both the overall and cumulative pause
deadlines. After the first hit, the one-shot entry breakpoint is removed before tracing continues.
On completion or failure, cleanup disables exception pauses before sending the final resume, then
closes the inspector and the owned Cloud Foundry tunnel. If both tracing and cleanup fail, the CLI
reports CLEANUP_FAILED and explicitly says when resume could not be confirmed. An unreachable
inspector cannot provide an absolute real-time resume guarantee, so production tracing still
requires explicit impact confirmation and conservative limits. Session disposal preserves the
primary operation failure together with inspector and tunnel cleanup failures instead of allowing a
later finally error to hide an earlier cause.
Errors
Every command prints one JSON object: a result on stdout, or {"error":{"code":...,"message":...}}
on stderr with exit code 2 (usage or data errors, including Commander's own parse errors such as an
unknown flag or a missing required option) or 1 (an unexpected failure). A bare invocation with no
arguments prints the command list to stdout and still exits 1; nothing is ever silent.
INVALID_RUN_ID: the run selector itself is malformed (notlatest, nottfollowed by 16 lowercase hex characters) — checked before any lookup is attempted.RUN_NOT_FOUND: the ID is well-formed but no run exists at that ID (expired, purged, or never created).AMBIGUOUS_FUNCTION: the selector matches more than one function in the file. The error'scandidatesarray lists each match's exactselector(use it verbatim to retry),kind, andstartLine/endLine, instead of leaving the caller to guess a more specific name.SESSION_ALREADY_RUNNING: a tunnel already exists for this exact app/process/instance, thrown before any run is created. Runcf-debugger listto see it, thencf-debugger stop <app>before retrying.- Partial run on
MAX_PAUSED_TIMEorTRACE_TIMEOUT: real, recoverable data is still on disk. The thrown error carriesrunIdanddirectoryfields alongsidecode/message, so the run can still beshown,stated, anddiffed without a separaterunslookup. Hitting--max-stepsis not an error at all:recordexits normally with"status":"partial"in its stdout summary. CLEANUP_FAILED: both the traced operation and its cleanup failed; the message says whether resume could not be confirmed. Treat the target app as possibly still paused until verified otherwise.
See "Stopping a backgrounded record" above for the SIGTERM-not-SIGKILL rule when a record needs
to be stopped early instead of failing on its own.
Library API
The package exports the planner, controller ports, inspector adapter, state capture/diff helpers, run reader/store, recorder, and local/Cloud Foundry session lifecycle. Public locations use the Chrome DevTools Protocol's zero-based line and column convention; CLI plan output is one-based for terminal readability.
Current boundary
Version 0.2.x traces one selected activation — synchronous or asynchronous — in one Node.js
isolate. Async support uses V8's async-aware stepping and stays bound to the selected activation
across await; because settling awaited I/O requires briefly resuming the shared isolate, an async
trace is an interleaved sequence of frozen snapshots rather than one atomic frozen window, and
unrelated production work runs during each await gap. Following --call-depth into asynchronous
child calls, for await ... of loops, tracing multiple workers at once, generating traffic, and
mapping bundled code back through source maps are still out of scope. It also cannot cancel every
already-running filesystem or CDP promise after a watchdog fires. Choose a target/worker explicitly
where needed, prefer --match on busy targets, and trigger the relevant request only after the
armed event.
No live Cloud Foundry environment is used by the automated tests. The local E2E suite drives a real Node.js inspector and covers normal, exception, and termination paths. The fake-CF suite verifies remote selector forwarding and cleanup without credentials or SAP network access.
History
Other 1
Notes
- Accept the self-updating releases of
@saptools/cf-inspectoras dependencies (range widened, no behaviour change).
Other 1
Notes
- Self-updating. Every command now checks npm for a newer
@saptools/cf-function-trace(at most once an hour) and, when one exists, installs that exact version and re-runs the command on it, announcing both steps on stderr.SAPTOOLS_AUTO_UPDATE=on|notify|offcontrols it (see the README's Updates section); it is off by itself in CI, in tests, from a source checkout and inside the re-run. Newcf-function-trace self-update [--check]forces the check and install now.--versionnow readspackage.jsonat runtime. Both come from the private, build-time-bundled@saptools/corepackage; the published tarball gains no runtime dependency.
- Self-updating. Every command now checks npm for a newer
Fixes 1
Notes
Fix
- Revert the per-capture
getPropertiesprefetch that shipped in 0.2.6. It could leave a warmed request in flight when its object was released, so the WebSocket handle kept the CLI process alive and a trace could fail to exit (surfaced as a flaky runtime-e2e timeout on the CI runners). The machinery-shallow capture default from 0.2.6 is unchanged and remains the performance fix.
- Revert the per-capture
Performance 1
Notes
Performance
- Capture "machinery" (framework/behavioral) objects shallowly by default, so a step no longer
descends the entire service graph. An object V8 gives a constructed className other than
Object/Array— the CAP service instance (this), acds.Request(req), loggers, services — is now walked only--machinery-depthlevels (default 1) instead of the full--max-object-depth, whether it is a root or nested. PlainObject/Arraydata (the request payload and user locals) is still captured to--max-object-depth. Previouslythisalone expanded to ~570 nodes per step, the main driver of slow, timeout-prone captures. Raise--machinery-depth(with--max-object-depth) to recover full framework visibility on demand, so nothing is permanently lost. Every step is still captured fresh, so values are never stale.
- Capture "machinery" (framework/behavioral) objects shallowly by default, so a step no longer
descends the entire service graph. An object V8 gives a constructed className other than
Other 1
Notes
Diff granularity
- Node ids are now derived from each value's path in the captured graph instead of a per-capture
discovery-order counter, so the same logical object keeps a stable id across steps. This removes the
spurious node churn that made a baseline-anchored
diff(from the first captured step to a later one) collapse into a single whole-frame replace; those diffs are now granular per changed leaf, and a variable that never changed no longer appears in the diff.
- Node ids are now derived from each value's path in the captured graph instead of a per-capture
discovery-order counter, so the same logical object keeps a stable id across steps. This removes the
spurious node churn that made a baseline-anchored
Fixes 4, Docs 1, Other 5
Notes
Capture and diff correctness
- Diffs no longer collapse to a whole-frame replace. The incomplete-node removal safety net in the differ is now scoped to direct-child removals, so a truncated node no longer forces its entire subtree to re-emit. Real captures now produce granular per-step operations instead of one large replace blob.
- The capture budget is spent on the data that matters. Roots are captured in priority order (return
value, own parameters and locals, block locals,
this) with a per-root ceiling, so the request payload and user locals are no longer starved tonode-limitby framework objects such as loggers and the CAP service graph. - Function
descriptionvalues are hard-capped instead of dumping full function source into every step, cutting capture size and the repeated per-step serialization behind mid-trace timeouts. - Split the overloaded
--max-propertiesinto--max-root-vars(root and local count) and--max-properties(per-object fan-out).
CLI error contract
- A mistyped or missing flag now emits a structured JSON error on stderr with a non-zero exit, instead of exiting silently with no output.
stateanddiffresponses that exceed--max-output-bytesnow preserve the request envelope and include a hint (narrow with--path, or raise--max-output-bytes) instead of returning a content-free stub.- Errors are actionable: parse errors,
AMBIGUOUS_FUNCTIONcandidate lists, the operationalSESSION_ALREADY_RUNNINGguidance, andRUN_NOT_FOUND(with no leaked filesystem paths) are surfaced. - A
recordthat times out now attaches the partial run id to the error so the captured partial timeline can still be read.
Privacy
- Redaction now covers email and PII patterns and an optional
CF_FUNCTION_TRACE_SENSITIVE_KEYSkey list, in addition to credential-shaped secrets. Note: because redaction also runs during replay-hash verification, trace runs captured before 0.2.3 can report a state hash mismatch when read; re-record to get a clean run.
Documentation
- Added a cf-function-trace skill and expanded the README with the non-interactive record recipe, the
output and error reference, and the flag reference. A backgrounded
recordmust be stopped with SIGTERM, never SIGKILL, until the debugger self-heals an orphaned tunnel.
Other 1
Notes
Reliability
- Guarantee the target app resumes and the SSH tunnel is torn down on every termination path. An
uncaught exception or rejection (for example during a large state capture) previously bypassed
cleanup, and a signal-driven stop had only implicit protection — either could leave V8 paused and
the
cf sshtunnel orphaned, freezing the app until the tunnel was killed by hand. A process-wide resource guard now releases the tunnel, inspector session, and debugger state on SIGINT, SIGTERM,uncaughtException, andunhandledRejection, with a bounded forced-exit fallback and immediate escalation on a repeated signal.
- Guarantee the target app resumes and the SSH tunnel is torn down on every termination path. An
uncaught exception or rejection (for example during a large state capture) previously bypassed
cleanup, and a signal-driven stop had only implicit protection — either could leave V8 paused and
the
Other 1
Notes
- Require
@saptools/cf-inspector@^0.6.2(which pulls@saptools/cf-debugger@^0.1.16) so the async-stack-depth API and app-port Node auto-selection resolve from the published dependency chain.
- Require
Other 6
Notes
Async function tracing
- Trace
asyncfunctions and functions containingawait: V8's async-aware stepping stays bound to the one selected activation across eachawait, capturing and diffing the same per-step state timeline as synchronous traces. Unrelated pauses during an await gap are released and skipped. - Select methods of decorator-compiled class expressions (
let X = class X {...}), so decorated CAP and NestJS handlers resolve. - Add
--match <expr>, a conditional entry breakpoint that traces only an activation whose entry frame satisfies the expression, correlating one request amid concurrent traffic (sync and async). - Add
--async-stack-depth <count>and request async call-stack depth for async traces. - Auto-select the app
$PORTNode process through the tunnel, so--node-pidis usually unnecessary when an instance runs several Node processes. - Raise the
--max-paused-msceiling to 600000 for deeper remote captures.
- Trace
Other 4
Notes
- Require the registry-compatible
@saptools/cf-inspector@^0.6.0dependency chain. - Add GitHub Actions trusted publishing after quality and Node.js 20/22/24 runtime gates.
- Verify the publish candidate alone in a clean consumer so dependencies resolve from npm.
- Replace workspace-only installation documentation with the public npm workflow.
- Require the registry-compatible
Other 13
Notes
- Add local and explicitly confirmed SAP BTP Cloud Foundry inspector targets.
- Resolve exact loaded scripts and uniquely selected synchronous functions.
- Trace app-owned call depth 0–2 with bounded stepping, one-shot entry breakpoints, and ownership-aware cleanup.
- Capture side-effect-free tagged object graphs with stable scope identities, strict serialized-state bounds, and redaction before persistence.
- Store full checkpoints, granular array/object patches, source/state hashes, append-only events, exact replay validation, query-triggered retention, per-run quotas, and private modes.
- Record exception pauses distinctly and watchdog capture, persistence, stepping, and cleanup.
- Add compact
plan,record, paginatedshow, exactstate,diff,runs, andpurgecommands. - Mark internal-slot values incomplete, expand credential redaction, and name the copied terminal
checkpoint
completedinstead of incorrectly claiming a captured return value. - Prevent remote tracing from enabling SSH or restarting an app implicitly.
- Return a stable, redacted
SSH_NOT_ENABLEDerror and aggregate operation, inspector, and tunnel cleanup failures without masking earlier causes. - Add an optional validated
--tunnel-portthat forwards to the debugger's existing preferred-port API without changing default port allocation. - Add unit coverage, normal/failure local-inspector and fake-CF E2E coverage, and Node.js 20/22/24 CI.
- Verify the package with coordinated debugger, inspector, and function-trace tarballs.
Others providing
Compare all 22 on the Debugging page →- dbg_value_statementdbg_value_statementAn ABAP Debugger script that turns a variable's structure or table into the VALUE statement that recreates it, with a tree explorer, also callable as a function module from a report.independent, abapDebugger script generating a VALUE statement for a variablefrom ABAP
- dump_infodump_infoDisplays the variables an ABAP short dump captured, for dumps selected on a selection screen; its documentation does not state which dumps it reads, which releases it runs on or how it installs.independent, abapDisplays the variables of ABAP short dumpsfrom ABAP
- com.sap.cds:cds-feature-consolecom.sap.cds:cds-feature-consoleA CAP Java plugin that connects a running application to CAP console, which consumes its remote monitoring data; CAP console itself is installed separately and still being developed.sap official, capConnects a running CAP Java app to CAP console for monitoringfrom CAP
- com.sap.cds:cds-feature-dev-dashboardcom.sap.cds:cds-feature-dev-dashboardA browser dashboard for a running CAP Java service that shows and manages its messaging, resilience and multitenancy state while developing, open to users with the cds.Developer role.sap official, capBrowser dashboard for a running CAP Java service during developmentfrom CAP
- @cap-js/console@cap-js/consoleConnects a running CAP application to the CAP console.sap official, capConnects a running CAP application to the CAP consolefrom CAP
- @cap-js/data-inspector@cap-js/data-inspectorInspects database entities and their contents at the CAP service level.sap official, capInspects database entities and contents at CAP service levelfrom CAP
- abapsmithabapsmithAn MCP server that lets an LLM develop in ABAP on a live system over ADT, with writes off by default and every mutation recorded in a local journal that can undo it.independent, abapABAP MCP server over ADT with a local journal that can undo writesfrom ABAP
- sap-cap-debuggersap-cap-debuggerAttaches a debugger to a CAP application already running on Cloud Foundry — enables the Node inspector inside the container, assigns a port and hands you a Chrome DevTools or VS Code attach.independent, capAttaches a debugger to a CAP app running on Cloud Foundryfrom CAP
- ABAP-Object-VisualizerABAP-Object-VisualizerA debugger script that writes an object hierarchy to the clipboard at a breakpoint as a Graphviz description, for pasting into a renderer such as webgraphviz.com.independent, abapDebugger script exporting an object hierarchy as Graphvizfrom ABAP
- abap_debugger_object_graph_extensionabap_debugger_object_graph_extensionAn ABAP debugger extension that shows the object on the debugger's Objects tab as a Graphviz graph in a browser window, built on ABAP Graph and Graphviz-browser and tested on NetWeaver 7.5.independent, abapABAP debugger extension drawing objects as a Graphviz graphfrom ABAP
- Graphviz-browserGraphviz-browserA static page that draws a Graphviz graph in a browser, written for the ABAP debugger object graph extension and deployable as BSP pages in the system the debugger runs in.independent, abapStatic page drawing Graphviz graphs for the ABAP debugger extensionfrom ABAP
- ABAP remote filesystemABAP remote filesystemA Visual Studio Code extension that opens an ABAP system over ADT as an editable filesystem and exposes system tools to GitHub Copilot and external MCP clients.independent, abapVS Code extension editing ABAP systems over ADT as a filesystemfrom ABAP
- @sap/cds-dk@sap/cds-dkThe command line client and development toolkit for CAP projects, with the commands cds build, cds deploy, cds watch and cds add among them.sap official, capCommand line client and development toolkit for CAPfrom CAP
- @saptools/cf-debugger@saptools/cf-debuggerOpens a verified Node.js inspector tunnel over cf ssh to an app on SAP BTP Cloud Foundry from one command, with its own local port for each concurrent session.independent, btpNode.js inspector tunnel over cf ssh to Cloud Foundry appsfrom BTP/BAIP
- @saptools/cf-explorer@saptools/cf-explorerSearches the files of an app deployed to SAP BTP Cloud Foundry over cf ssh, finding the app root, grepping the deployed code and turning matches into file and line candidates.independent, btpFile search in apps deployed to SAP BTP Cloud Foundry over cf sshfrom BTP/BAIP
- @saptools/cf-hana@saptools/cf-hanaA command line and TypeScript API that runs SQL against the SAP HANA Cloud database bound to a Cloud Foundry app, addressed by a region/org/space/app selector.independent, btpSQL runner against the SAP HANA Cloud database bound to a CF appfrom BTP/BAIP
- @saptools/cf-inspector@saptools/cf-inspectorSets breakpoints, captures variable snapshots and evaluates expressions on a remote Node.js process over the Chrome DevTools Protocol from the shell, with no IDE attached.independent, btpShell debugger for remote Node.js over the Chrome DevTools Protocolfrom BTP/BAIP
- @saptools/cf-live-trace@saptools/cf-live-traceInjects a bounded HTTP trace hook into a running Node.js app on SAP BTP Cloud Foundry and streams each request and response to the terminal as JSON.independent, btpHTTP trace hook streaming a running CF Node.js app's trafficfrom BTP/BAIP
- @saptools/cf-request-runner@saptools/cf-request-runnerDiscovers every API endpoint of a CAP service already deployed to Cloud Foundry by walking its service documents, $metadata and endpoints catalog — falling back to container SSH to parse .cds files.independent, capEndpoint discovery for CAP services deployed to Cloud Foundryfrom CAP
- @saptools/service-flow@saptools/service-flowTraces one CAP operation end to end across several repositories without running anything — handlers, helper packages, local database access, remote OData calls, external HTTP and async channels.independent, capStatic end-to-end tracer of one CAP operation across repositoriesfrom CAP
- Smart DebuggerSmart DebuggerA debugger script for the SAP GUI New Debugger that records every step and variable change of an ABAP program, so execution can be stepped backwards with F5 and F8.independent, abapSAP GUI debugger script recording steps so execution can run backwardsfrom ABAP
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
History in the atlas
- First seen.
For your agent
- Ref
artifact:saptools-cf-function-trace- JSON
- /artifacts/saptools-cf-function-trace.json
- MCP
- Connecting an agent