@ishlabs/cli 0.17.5 → 0.17.7
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/dist/lib/command-helpers.js +34 -16
- package/dist/lib/observability.d.ts +11 -0
- package/dist/lib/observability.js +25 -3
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ import { outputError, setVerbose, setFields, setGetField } from "./output.js";
|
|
|
10
10
|
import { setColorsEnabled, colorsEnabled } from "./colors.js";
|
|
11
11
|
import { loadConfig } from "../config.js";
|
|
12
12
|
import { resolveId } from "./alias-store.js";
|
|
13
|
-
import { exitWithFlush } from "./observability.js";
|
|
13
|
+
import { exitWithFlush, withCliSpan } from "./observability.js";
|
|
14
14
|
function isSimulatable(p) {
|
|
15
15
|
return Boolean(p.simulation_config_id) || Boolean(p.simulation_config);
|
|
16
16
|
}
|
|
@@ -406,16 +406,32 @@ function applyGlobals(globals) {
|
|
|
406
406
|
setColorsEnabled(globals.color);
|
|
407
407
|
_activeWorkspace = globals.workspace;
|
|
408
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Build the dotted command path (`workspace.list` rather than just `list`)
|
|
411
|
+
* for the root-span name. Mirrors the walk in the program's `preAction`
|
|
412
|
+
* baggage hook so span names line up with `client.surface` on the backend.
|
|
413
|
+
*/
|
|
414
|
+
function commandPath(cmd) {
|
|
415
|
+
const parts = [];
|
|
416
|
+
let c = cmd;
|
|
417
|
+
while (c && c.parent) {
|
|
418
|
+
parts.unshift(c.name());
|
|
419
|
+
c = c.parent;
|
|
420
|
+
}
|
|
421
|
+
return parts.join(".") || cmd.name();
|
|
422
|
+
}
|
|
409
423
|
export async function withClient(cmd, fn) {
|
|
410
424
|
const globals = getGlobals(cmd);
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
425
|
+
await withCliSpan(commandPath(cmd), async () => {
|
|
426
|
+
try {
|
|
427
|
+
const client = await createClient(globals);
|
|
428
|
+
await fn(client, globals);
|
|
429
|
+
}
|
|
430
|
+
catch (err) {
|
|
431
|
+
outputError(err, globals.json);
|
|
432
|
+
await exitWithFlush(exitCodeFromError(err));
|
|
433
|
+
}
|
|
434
|
+
});
|
|
419
435
|
}
|
|
420
436
|
/**
|
|
421
437
|
* Wrap an inline (non-API) command action with the same uniform error
|
|
@@ -424,13 +440,15 @@ export async function withClient(cmd, fn) {
|
|
|
424
440
|
*/
|
|
425
441
|
export async function runInline(cmd, fn) {
|
|
426
442
|
const globals = getGlobals(cmd);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
443
|
+
await withCliSpan(commandPath(cmd), async () => {
|
|
444
|
+
try {
|
|
445
|
+
await fn(globals);
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
outputError(err, globals.json);
|
|
449
|
+
await exitWithFlush(exitCodeFromError(err));
|
|
450
|
+
}
|
|
451
|
+
});
|
|
434
452
|
}
|
|
435
453
|
export function getWebUrl(globals, path) {
|
|
436
454
|
const base = globals.dev ? "http://localhost:3000" : getAppUrl();
|
|
@@ -43,6 +43,17 @@ export declare function initObservability(): Promise<void>;
|
|
|
43
43
|
* CLI.
|
|
44
44
|
*/
|
|
45
45
|
export declare function flushObservability(timeoutMs?: number): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Open a root transaction for a CLI command. `@sentry/node` only auto-creates
|
|
48
|
+
* transactions for HTTP server frameworks; arbitrary code paths need an
|
|
49
|
+
* explicit `startSpan` to anchor child spans (the UndiciInstrumentation
|
|
50
|
+
* fetch spans) so the exporter ships them. Without this wrap, every CLI
|
|
51
|
+
* run produces zero spans in the ish-cli Sentry project.
|
|
52
|
+
*
|
|
53
|
+
* No-op (passthrough) when Sentry isn't initialised — DSN unset or init
|
|
54
|
+
* failed — so the helper is always safe to call from withClient / runInline.
|
|
55
|
+
*/
|
|
56
|
+
export declare function withCliSpan<T>(commandName: string, fn: () => Promise<T>): Promise<T>;
|
|
46
57
|
/**
|
|
47
58
|
* Async-flush-then-exit helper. Use this in place of `process.exit(code)`
|
|
48
59
|
* anywhere we want telemetry to ship before teardown.
|
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import pkg from "../../package.json" with { type: "json" };
|
|
26
26
|
import { beforeSend } from "./sentry-scrub.js";
|
|
27
|
-
/** Module-local reference to the loaded Sentry module so `flushObservability`
|
|
28
|
-
* can call `flush()` without re-importing (which would lose runtime-pinned
|
|
29
|
-
* state and create a second Hub in some bundler configurations). */
|
|
30
27
|
let _sentryModule = null;
|
|
31
28
|
/** Bun-global probe. ``typeof Bun !== 'undefined'`` is the only reliable
|
|
32
29
|
* runtime-detect: ``process.versions.bun`` exists but is set up well after
|
|
@@ -76,6 +73,15 @@ export async function initObservability() {
|
|
|
76
73
|
setTag("client.name", "ish-cli");
|
|
77
74
|
setTag("client.version", pkg.version);
|
|
78
75
|
}
|
|
76
|
+
// Natural-exit flush hook. `process.exit()` paths are covered by
|
|
77
|
+
// `exitWithFlush`, but successful CLI commands return normally —
|
|
78
|
+
// Node tears the process down via `beforeExit` and there's no
|
|
79
|
+
// process.exit to wrap. This is the catch-all for that case.
|
|
80
|
+
// Use `once` so a command that explicitly calls exit doesn't
|
|
81
|
+
// double-flush.
|
|
82
|
+
process.once("beforeExit", () => {
|
|
83
|
+
void flushObservability();
|
|
84
|
+
});
|
|
79
85
|
}
|
|
80
86
|
catch (err) {
|
|
81
87
|
// Don't crash the CLI on init failure. Print to stderr at verbose
|
|
@@ -151,6 +157,22 @@ export async function flushObservability(timeoutMs = 2000) {
|
|
|
151
157
|
// Swallow — same rationale as init failure.
|
|
152
158
|
}
|
|
153
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Open a root transaction for a CLI command. `@sentry/node` only auto-creates
|
|
162
|
+
* transactions for HTTP server frameworks; arbitrary code paths need an
|
|
163
|
+
* explicit `startSpan` to anchor child spans (the UndiciInstrumentation
|
|
164
|
+
* fetch spans) so the exporter ships them. Without this wrap, every CLI
|
|
165
|
+
* run produces zero spans in the ish-cli Sentry project.
|
|
166
|
+
*
|
|
167
|
+
* No-op (passthrough) when Sentry isn't initialised — DSN unset or init
|
|
168
|
+
* failed — so the helper is always safe to call from withClient / runInline.
|
|
169
|
+
*/
|
|
170
|
+
export async function withCliSpan(commandName, fn) {
|
|
171
|
+
if (!_initialized || _sentryModule?.startSpan === undefined) {
|
|
172
|
+
return await fn();
|
|
173
|
+
}
|
|
174
|
+
return await _sentryModule.startSpan({ name: `cli.${commandName}`, op: "cli.command" }, async () => await fn());
|
|
175
|
+
}
|
|
154
176
|
/**
|
|
155
177
|
* Async-flush-then-exit helper. Use this in place of `process.exit(code)`
|
|
156
178
|
* anywhere we want telemetry to ship before teardown.
|