@saptools/cf-inspector 0.6.2 โ†’ 0.7.1

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 CHANGED
@@ -16,6 +16,15 @@ Built so an AI agent (or a CI job) can drive a debugger from a single shell comm
16
16
 
17
17
  ---
18
18
 
19
+ > **Debug-session safety:** only one local `cf-inspector` process may actively
20
+ > debug a given target at a time. Concurrent CDP debugger clients can receive
21
+ > the same pause and race `Debugger.resume`, disrupting the target and real
22
+ > application traffic. A second local invocation now fails before connecting
23
+ > with `TARGET_ALREADY_DEBUGGED`; wait for the named owner process to finish.
24
+ > Locks left by dead processes are reclaimed automatically. Debuggers running
25
+ > on another machine or outside `cf-inspector` cannot be detected by this local
26
+ > guard and must still be coordinated operationally.
27
+
19
28
  ## โœจ Features
20
29
 
21
30
  - ๐ŸŽฏ **One-shot snapshot** โ€” `cf-inspector snapshot --bp src/handler.ts:42` sets the breakpoint, waits for it to hit, captures requested expressions, auto-resumes, prints JSON, exits
@@ -27,7 +36,7 @@ Built so an AI agent (or a CI job) can drive a debugger from a single shell comm
27
36
  - ๐Ÿ’ฅ **Exception breakpoints** โ€” `cf-inspector exception --type uncaught --capture err.message` pauses on the next thrown error and materializes the exception value
28
37
  - ๐Ÿ“ก **Non-pausing logpoints** โ€” `cf-inspector log --at file:line --expr 'JSON.stringify({โ€ฆ})'` streams JSON Lines as the line executes without pausing the inspectee, with optional `--condition`, `--hit-count`, and `--max-events`
29
38
  - ๐Ÿ›ก๏ธ **Read-only capture guard** โ€” snapshot, watch, and exception captures use V8's side-effect analysis by default; `--allow-mutation` is an explicit escape hatch
30
- - ๐Ÿงต **Worker-aware sessions** โ€” `list-targets` discovers raw inspector targets and nested NodeWorker sessions; use `--target` or `--worker` to select an isolate
39
+ - ๐Ÿงต **Automatic worker fan-out** โ€” snapshot, watch, exception, and log attach to the main isolate plus every current or newly-spawned NodeWorker; explicit selectors remain available for pinning
31
40
  - ๐Ÿง  **Agent-friendly** โ€” JSON-by-default I/O, deterministic shapes, and explicit `truncated`/`originalLength`/`omittedCount` metadata for bounded values
32
41
  - ๐Ÿงญ **Path mapping** โ€” local `src/handler.ts:42` is matched against the remote URL via a `urlRegex`, with optional `--remote-root` literal or regex (same DSL as `cds-debug`)
33
42
  - ๐Ÿ” **Composes with `cf-debugger`** โ€” pass `--app/--region/--org/--space` and the tunnel is opened automatically; pass `--port` to attach to anything CDP-speaking
@@ -73,6 +82,21 @@ Cloud Foundry targeting is deliberately deterministic: `--app` requires
73
82
  from ambient `cf target` state. Use `--api-endpoint` only when the selected
74
83
  region needs an explicit endpoint override.
75
84
 
85
+ ### Worker behavior
86
+
87
+ When no isolate selector is passed, `snapshot`, `watch`, `exception`, `log`, and
88
+ `check-breakpoint` attach to the main isolate and every NodeWorker under the
89
+ selected raw target. Breakpoints are mirrored to workers that attach later, the
90
+ first matching pause wins, and JSON/human output identifies the winning
91
+ `isolate` as either `{"kind":"main"}` or
92
+ `{"kind":"worker","workerId":"โ€ฆ"}`. Losing isolates that also paused are
93
+ resumed before the command continues or exits.
94
+
95
+ Use `--worker-id <id>` to pin a stable live worker ID from `list-targets`,
96
+ `--worker <index>` for the legacy positional selector, `--target <index>` to
97
+ pin a raw inspector target, or `--main-only` to deliberately ignore workers.
98
+ Explicit selectors preserve single-isolate behavior.
99
+
76
100
  ---
77
101
 
78
102
  ## ๐Ÿงฐ CLI
@@ -103,6 +127,8 @@ cf-inspector snapshot --port 9229 \
103
127
  | `--api-endpoint <url>` | Override the API endpoint resolved from `--region` |
104
128
  | `--target <index>` | Raw `/json/list` target index (default: `0`) |
105
129
  | `--worker <index>` | Nested NodeWorker index reported under the selected raw target by `list-targets` |
130
+ | `--worker-id <id>` | Stable live NodeWorker ID reported by `list-targets` |
131
+ | `--main-only` | Attach only to the main isolate and ignore NodeWorkers |
106
132
  | `--bp <file:line>` | **Required.** Source location to break at. Pass multiple times to race several locations โ€” the first one to hit wins |
107
133
  | `--condition <expr>` | Native breakpoint condition. It is compile-checked before arming; mutation-shaped conditions require `--allow-mutation` because CDP provides no side-effect guard for native conditions |
108
134
  | `--hit-count <n>` | Skip the first N โˆ’ 1 hits and only pause on the Nth (combines with `--condition` via logical AND) |
@@ -232,7 +258,8 @@ When the user expression throws, the event is emitted with `error` instead of `v
232
258
  | Flag | Description |
233
259
  | --- | --- |
234
260
  | `--port <number>` | Local port the inspector or tunnel listens on. **Required** unless `--app/--region/--org/--space` are all set |
235
- | `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
261
+ | `--target <index>` / `--worker <index>` / `--worker-id <id>` | Pin one raw target or worker instead of automatic fan-out |
262
+ | `--main-only` | Ignore workers and attach only to the main isolate |
236
263
  | `--at <file:line>` | **Required.** Source location to log at |
237
264
  | `--expr <expression>` | **Required.** JavaScript expression evaluated at each hit, wrapped in try/catch on the inspectee side. It is mutation-capable; recognizable risks produce a warning |
238
265
  | `--duration <seconds>` | Stop streaming after N seconds (default: run until SIGINT) |
@@ -275,7 +302,8 @@ Each event is a `WatchEvent`:
275
302
  | Flag | Description |
276
303
  | --- | --- |
277
304
  | `--port <number>` | Local port the inspector or tunnel listens on. Otherwise pass all explicit Cloud Foundry selectors |
278
- | `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
305
+ | `--target <index>` / `--worker <index>` / `--worker-id <id>` | Pin one raw target or worker instead of automatic fan-out |
306
+ | `--main-only` | Ignore workers and attach only to the main isolate |
279
307
  | `--bp <file:line>` | **Required.** Source location to capture on (repeatable) |
280
308
  | `--capture <expr,โ€ฆ>` | Top-level comma-separated expressions evaluated per hit under V8's side-effect guard |
281
309
  | `--setup-eval <expr>` | Repeatable mutation-capable global expression evaluated before breakpoint setup; recognizable risks produce a warning |
@@ -324,7 +352,8 @@ Result is a `SnapshotResult` with an extra `exception` field:
324
352
  | Flag | Description |
325
353
  | --- | --- |
326
354
  | `--port` or explicit `--region/--org/--space/--app` | Select the local inspector or deterministic Cloud Foundry target |
327
- | `--target <index>` / `--worker <index>` | Select a raw inspector target or nested NodeWorker session from `list-targets` |
355
+ | `--target <index>` / `--worker <index>` / `--worker-id <id>` | Pin one raw target or worker instead of automatic fan-out |
356
+ | `--main-only` | Ignore workers and attach only to the main isolate |
328
357
  | `--type <state>` | Pause on which exceptions: `uncaught` (default), `caught`, or `all` |
329
358
  | `--capture <expr,โ€ฆ>` | Top-level expressions evaluated in the paused frame under V8's side-effect guard |
330
359
  | `--stack-depth <n>` | Walk this many call frames (default: `1`) |
@@ -368,7 +397,8 @@ nested workers with their own indexes.
368
397
 
369
398
  ```bash
370
399
  cf-inspector list-targets --port 9229
371
- cf-inspector snapshot --port 9229 --worker 0 --bp dist/worker.js:42
400
+ cf-inspector snapshot --port 9229 --bp dist/worker.js:42
401
+ cf-inspector snapshot --port 9229 --worker-id 1 --bp dist/worker.js:42
372
402
  # If a runtime publishes a worker as another raw /json/list target instead:
373
403
  cf-inspector snapshot --port 9229 --target 1 --bp dist/worker.js:42
374
404
  ```
@@ -394,23 +424,38 @@ JSON output nests workers beneath their raw target:
394
424
  ]
395
425
  ```
396
426
 
397
- `--target` selects a complete raw inspector endpoint. `--worker` selects a
398
- nested NodeWorker session under the chosen raw target (raw target `0` unless
399
- `--target` is also passed). Modern Node.js 20โ€“25 verification found workers on
427
+ `--target` selects a complete raw inspector endpoint. `--worker-id` selects a
428
+ live nested worker by its stable ID, while `--worker` retains positional-index
429
+ selection for compatibility. Modern Node.js 20โ€“25 verification found workers on
400
430
  the `NodeWorker` path, including workers already alive before post-hoc
401
431
  `SIGUSR1` inspector activation; the raw-target selector remains supported for
402
432
  runtimes that publish that shape.
403
433
 
404
- When multiple raw targets or nested workers exist and no selector is passed,
405
- commands attach to raw target `0` and print a selection notice. A bound
406
- breakpoint that sees no hit prints a worker-isolate hint. If only one raw target
434
+ When no selector is passed, breakpoint-oriented commands attach to raw target
435
+ `0` and automatically fan out across its main isolate and nested workers. If only one raw target
407
436
  and no workers are visible, `list-targets` explains that the worker may have
408
437
  exited, the runtime may not expose NodeWorker discovery, or a separate worker
409
438
  port may be unreachable through the single Cloud Foundry tunnel. Rerun the
410
- command while the worker is alive before selecting an index.
439
+ command while the worker is alive before pinning its `workerId`.
411
440
 
412
441
  If `list-targets`, `attach`, or another command reports `ECONNREFUSED`, the local inspector or tunnel on that port is usually stale/closed. Restart the local Node inspector or tunnel and retry; for Cloud Foundry targets, pass the complete `--region/--org/--space/--app` selector so `cf-inspector` can open a fresh tunnel.
413
442
 
443
+ ### โœ… `cf-inspector check-breakpoint`
444
+
445
+ Check whether a `file:line` can accept a breakpoint before arming one. The
446
+ command uses the same path mapping as `--bp` and checks every currently attached
447
+ isolate by default.
448
+
449
+ ```bash
450
+ cf-inspector check-breakpoint --port 9229 --bp dist/handler.js:42
451
+ ```
452
+
453
+ `status: "script-not-loaded"` means no loaded script matched the file/path
454
+ mapping; use `list-scripts`, adjust `--remote-root`, or trigger lazy loading.
455
+ `status: "unbreakable"` means the script is loaded but that exact line has no
456
+ V8 break location; choose a neighboring executable line. `status: "breakable"`
457
+ includes the concrete script IDs, isolate identities, lines, and columns.
458
+
414
459
  ### ๐Ÿ”— `cf-inspector attach`
415
460
 
416
461
  Connect, fetch the runtime version, print it, disconnect. Useful as a smoke-test that the tunnel is healthy.
@@ -480,7 +525,7 @@ pre-existing session.
480
525
  ```
481
526
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” 1. GET http://127.0.0.1:<port>/json/list
482
527
  โ”‚ cf-inspector โ”‚ 2. Open the selected raw WebSocket target
483
- โ”‚ snapshot --bp X:Y โ”‚ โ”€โ–บ3. Optionally attach to a selected NodeWorker sub-session
528
+ โ”‚ snapshot --bp X:Y โ”‚ โ”€โ–บ3. Auto-attach to current and future NodeWorker sub-sessions
484
529
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ 4. Debugger.enable + Runtime.enable
485
530
  โ”‚ 5. Debugger.setBreakpointByUrl({ urlRegex, lineNumber: Y - 1 })
486
531
  โ–ผ 6. Wait for `Debugger.paused`
@@ -510,7 +555,8 @@ CLI does not read ambient `cf target` state. It calls `startDebugger(...)` from
510
555
  on exit. You get the same one-shot UX whether the target is local or in CF.
511
556
 
512
557
  The tunnel forwards one inspector port. Nested NodeWorker sessions carried by
513
- that inspector connection are selectable with `--worker`; a worker exposing
558
+ that inspector connection are auto-attached by breakpoint-oriented commands and
559
+ can be pinned with `--worker-id`; a worker exposing
514
560
  only an unrelated separate port is outside that tunnel's reach.
515
561
 
516
562
  ```bash