@saptools/cf-inspector 0.4.11 → 0.4.12

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
@@ -40,6 +40,8 @@ Built so an AI agent (or a CI job) can drive a debugger from a single shell comm
40
40
  npm install -g @saptools/cf-inspector
41
41
  # or
42
42
  pnpm add @saptools/cf-inspector
43
+
44
+ cf-inspector --version
43
45
  ```
44
46
 
45
47
  > [!NOTE]
@@ -284,6 +286,8 @@ cf-inspector list-targets --port 9229
284
286
  cf-inspector snapshot --port 9229 --target 1 --bp dist/worker.js:42
285
287
  ```
286
288
 
289
+ 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, prefer `--app/--region/--org/--space` so `cf-inspector` can open a fresh tunnel.
290
+
287
291
  ### 🔗 `cf-inspector attach`
288
292
 
289
293
  Connect, fetch the runtime version, print it, disconnect. Useful as a smoke-test that the tunnel is healthy.
package/dist/cli.js CHANGED
@@ -155,6 +155,9 @@ var init_wsTransport = __esm({
155
155
  import process12 from "process";
156
156
 
157
157
  // src/cli/program.ts
158
+ import { readFileSync } from "fs";
159
+ import { dirname, join } from "path";
160
+ import { fileURLToPath } from "url";
158
161
  import { Command } from "commander";
159
162
 
160
163
  // src/cli/commands/attach.ts
@@ -190,16 +193,39 @@ async function fetchJson(url, timeoutMs) {
190
193
  );
191
194
  });
192
195
  req.on("error", (err) => {
193
- reject(
194
- err instanceof CfInspectorError ? err : new CfInspectorError(
195
- "INSPECTOR_DISCOVERY_FAILED",
196
- `Inspector discovery at ${url} failed: ${err.message}`
197
- )
198
- );
196
+ reject(err instanceof CfInspectorError ? err : formatDiscoveryRequestError(url, err));
199
197
  });
200
198
  req.end();
201
199
  });
202
200
  }
201
+ function isNodeSystemError(err) {
202
+ return err instanceof Error;
203
+ }
204
+ function isConnectionRefusedOrUnreachable(code) {
205
+ return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EHOSTUNREACH" || code === "ENETUNREACH";
206
+ }
207
+ function formatEndpoint(url, err) {
208
+ if (typeof err.address === "string" && typeof err.port === "number") {
209
+ return `${err.address}:${err.port.toString()}`;
210
+ }
211
+ const parsed = new URL(url);
212
+ return parsed.host;
213
+ }
214
+ function formatDiscoveryRequestError(url, err) {
215
+ const detail = err instanceof Error ? err.message : String(err);
216
+ if (!isNodeSystemError(err) || !isConnectionRefusedOrUnreachable(err.code)) {
217
+ return new CfInspectorError(
218
+ "INSPECTOR_DISCOVERY_FAILED",
219
+ `Inspector discovery at ${url} failed: ${detail}`
220
+ );
221
+ }
222
+ const endpoint = formatEndpoint(url, err);
223
+ return new CfInspectorError(
224
+ "INSPECTOR_DISCOVERY_FAILED",
225
+ `Cannot reach Node inspector discovery at ${url}. Nothing is listening on ${endpoint}, or the inspector tunnel is stale/closed. Restart the local inspector or tunnel and retry. If this port came from cf-debugger, stop the stale session and start a fresh tunnel, or run cf-inspector with --app/--region/--org/--space so it can open a tunnel.`,
226
+ detail
227
+ );
228
+ }
203
229
  function parseJsonResponse(chunks) {
204
230
  const text = Buffer.concat(chunks).toString("utf8");
205
231
  return JSON.parse(text);
@@ -2742,54 +2768,57 @@ function prepareSnapshotCommand(opts, target) {
2742
2768
  }
2743
2769
  async function runSnapshotCommand(command, opts, reportProgress) {
2744
2770
  return await withSession(command.target, async (session) => {
2745
- if (command.setupEvals.length > 0) {
2746
- const setupCount = command.setupEvals.length;
2747
- reportProgress?.(`Running ${setupCount.toString()} setup ${setupCount === 1 ? "evaluation" : "evaluations"}...`);
2748
- await runSetupEvals(session, command.setupEvals);
2749
- reportProgress?.("Setup evaluation complete.");
2750
- }
2751
- if (command.condition !== void 0) {
2752
- reportProgress?.("Validating the breakpoint condition...");
2753
- await validateExpression(session, command.condition);
2754
- reportProgress?.("Breakpoint condition is valid.");
2755
- }
2756
- const breakpointCount = command.breakpoints.length;
2757
- reportProgress?.(
2758
- `Setting ${breakpointCount.toString()} ${breakpointCount === 1 ? "breakpoint" : "breakpoints"}...`
2759
- );
2760
- const handles = await setCommandBreakpoints(session, command);
2761
- const resolvedCount = handles.reduce(
2762
- (total, handle) => total + handle.resolvedLocations.length,
2763
- 0
2764
- );
2765
- reportProgress?.(
2766
- `Breakpoint setup complete: ${resolvedCount.toString()} resolved ${resolvedCount === 1 ? "location" : "locations"}.`
2767
- );
2768
- warnOnUnboundBreakpoints(handles);
2769
- reportProgress?.(
2770
- `Waiting up to ${(command.timeoutMs / 1e3).toString()}s for a breakpoint hit...`
2771
- );
2772
- const pause = await waitForCommandPause(session, opts, handles, command.timeoutMs);
2773
- const captureCount = command.captures.length;
2774
- reportProgress?.(
2775
- `Breakpoint hit; capturing ${captureCount.toString()} ${captureCount === 1 ? "expression" : "expressions"}...`
2776
- );
2777
- const pausedStartedAt = pause.receivedAtMs ?? performance4.now();
2778
- const snapshot = await captureSnapshot(session, pause, {
2779
- captures: command.captures,
2780
- includeScopes: opts.includeScopes === true,
2781
- ...command.maxValueLength === void 0 ? {} : { maxValueLength: command.maxValueLength },
2782
- ...command.stackDepth === void 0 ? {} : { stackDepth: command.stackDepth },
2783
- stackCaptures: command.stackCaptures
2784
- });
2785
- if (opts.keepPaused === true) {
2786
- reportProgress?.("Snapshot captured; leaving the target paused as requested.");
2787
- return withPausedDuration(snapshot, null);
2788
- }
2789
- reportProgress?.("Snapshot captured; resuming the target...");
2790
- return await resumeAfterSnapshot(session, snapshot, pausedStartedAt, reportProgress);
2771
+ return await runSnapshotOnSession(session, command, opts, reportProgress);
2791
2772
  }, reportProgress);
2792
2773
  }
2774
+ async function runSnapshotOnSession(session, command, opts, reportProgress) {
2775
+ if (command.setupEvals.length > 0) {
2776
+ const setupCount = command.setupEvals.length;
2777
+ reportProgress?.(`Running ${setupCount.toString()} setup ${setupCount === 1 ? "evaluation" : "evaluations"}...`);
2778
+ await runSetupEvals(session, command.setupEvals);
2779
+ reportProgress?.("Setup evaluation complete.");
2780
+ }
2781
+ if (command.condition !== void 0) {
2782
+ reportProgress?.("Validating the breakpoint condition...");
2783
+ await validateExpression(session, command.condition);
2784
+ reportProgress?.("Breakpoint condition is valid.");
2785
+ }
2786
+ const breakpointCount = command.breakpoints.length;
2787
+ reportProgress?.(
2788
+ `Setting ${breakpointCount.toString()} ${breakpointCount === 1 ? "breakpoint" : "breakpoints"}...`
2789
+ );
2790
+ const handles = await setCommandBreakpoints(session, command);
2791
+ const resolvedCount = handles.reduce(
2792
+ (total, handle) => total + handle.resolvedLocations.length,
2793
+ 0
2794
+ );
2795
+ reportProgress?.(
2796
+ `Breakpoint setup complete: ${resolvedCount.toString()} resolved ${resolvedCount === 1 ? "location" : "locations"}.`
2797
+ );
2798
+ warnOnUnboundBreakpoints(handles);
2799
+ reportProgress?.(
2800
+ `Waiting up to ${(command.timeoutMs / 1e3).toString()}s for a breakpoint hit...`
2801
+ );
2802
+ const pause = await waitForCommandPause(session, opts, handles, command.timeoutMs);
2803
+ const captureCount = command.captures.length;
2804
+ reportProgress?.(
2805
+ `Breakpoint hit; capturing ${captureCount.toString()} ${captureCount === 1 ? "expression" : "expressions"}...`
2806
+ );
2807
+ const pausedStartedAt = pause.receivedAtMs ?? performance4.now();
2808
+ const snapshot = await captureSnapshot(session, pause, {
2809
+ captures: command.captures,
2810
+ includeScopes: opts.includeScopes === true,
2811
+ ...command.maxValueLength === void 0 ? {} : { maxValueLength: command.maxValueLength },
2812
+ ...command.stackDepth === void 0 ? {} : { stackDepth: command.stackDepth },
2813
+ stackCaptures: command.stackCaptures
2814
+ });
2815
+ if (opts.keepPaused === true) {
2816
+ reportProgress?.("Snapshot captured; leaving the target paused as requested.");
2817
+ return withPausedDuration(snapshot, null);
2818
+ }
2819
+ reportProgress?.("Snapshot captured; resuming the target...");
2820
+ return await resumeAfterSnapshot(session, snapshot, pausedStartedAt, reportProgress);
2821
+ }
2793
2822
  async function setCommandBreakpoints(session, command) {
2794
2823
  return await Promise.all(
2795
2824
  command.breakpoints.map(
@@ -3075,9 +3104,27 @@ var collectStrings = (value, prev = []) => [
3075
3104
  ...prev,
3076
3105
  value
3077
3106
  ];
3107
+ function readPackageVersion() {
3108
+ let current = dirname(fileURLToPath(import.meta.url));
3109
+ for (let depth = 0; depth < 4; depth += 1) {
3110
+ const candidate = join(current, "package.json");
3111
+ try {
3112
+ const parsed = JSON.parse(readFileSync(candidate, "utf8"));
3113
+ if (typeof parsed === "object" && parsed !== null) {
3114
+ const record = parsed;
3115
+ if (record["name"] === "@saptools/cf-inspector" && typeof record["version"] === "string") {
3116
+ return record["version"];
3117
+ }
3118
+ }
3119
+ } catch {
3120
+ }
3121
+ current = dirname(current);
3122
+ }
3123
+ throw new Error("Unable to read @saptools/cf-inspector package version");
3124
+ }
3078
3125
  async function main(argv) {
3079
3126
  const program = new Command();
3080
- program.name("cf-inspector").description("Drive a Node.js inspector from the command line \u2014 set breakpoints, capture snapshots, evaluate expressions");
3127
+ program.name("cf-inspector").version(readPackageVersion()).description("Drive a Node.js inspector from the command line \u2014 set breakpoints, capture snapshots, evaluate expressions");
3081
3128
  registerSnapshot(program);
3082
3129
  registerLog(program);
3083
3130
  registerWatch(program);