@lorekit/cli 1.6.0 → 1.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/package.json +1 -1
- package/src/doctor.mjs +4 -2
- package/src/telemetry.mjs +37 -4
package/package.json
CHANGED
package/src/doctor.mjs
CHANGED
|
@@ -24,8 +24,9 @@ export async function doctor(args) {
|
|
|
24
24
|
const root = resolveProjectRoot(args.dir);
|
|
25
25
|
let failures = 0;
|
|
26
26
|
let warnings = 0;
|
|
27
|
+
const failedChecks = [];
|
|
27
28
|
const record = (kind, label, detail) => {
|
|
28
|
-
if (kind === 'fail') failures++;
|
|
29
|
+
if (kind === 'fail') { failures++; failedChecks.push(label); }
|
|
29
30
|
if (kind === 'warn') warnings++;
|
|
30
31
|
status(kind, label, detail);
|
|
31
32
|
};
|
|
@@ -91,7 +92,8 @@ export async function doctor(args) {
|
|
|
91
92
|
}.`,
|
|
92
93
|
);
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
const exitCode = failures === 0 ? 0 : 1;
|
|
96
|
+
return { exitCode, 'lorekit.cli.doctor.failed_checks': failedChecks };
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
// Merge doctor's --endpoint / --token flags into the env the resolver reads, so
|
package/src/telemetry.mjs
CHANGED
|
@@ -135,12 +135,13 @@ function resourceAttributes(version) {
|
|
|
135
135
|
* Collect the bounded, non-PII attributes for a command invocation. Only the
|
|
136
136
|
* command name, allow-listed boolean flags, the outcome and the exit code.
|
|
137
137
|
*/
|
|
138
|
-
export function commandAttributes({ command, args = {}, outcome, exitCode }) {
|
|
138
|
+
export function commandAttributes({ command, args = {}, outcome, exitCode, extraAttrs = {} }) {
|
|
139
139
|
const attrs = { 'lorekit.cli.command': command, 'lorekit.cli.outcome': outcome };
|
|
140
140
|
if (typeof exitCode === 'number') attrs['lorekit.cli.exit_code'] = exitCode;
|
|
141
141
|
for (const flag of FLAG_ATTRS) {
|
|
142
142
|
if (args[flag]) attrs[`lorekit.cli.flag.${flag}`] = true;
|
|
143
143
|
}
|
|
144
|
+
Object.assign(attrs, extraAttrs);
|
|
144
145
|
return attrs;
|
|
145
146
|
}
|
|
146
147
|
|
|
@@ -255,6 +256,19 @@ function errorLabel(e) {
|
|
|
255
256
|
return 'Error';
|
|
256
257
|
}
|
|
257
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Coerce a command handler's return value to a numeric exit code. Commands may
|
|
261
|
+
* resolve to a bare number, or to an { exitCode, ...extra } object (which lets
|
|
262
|
+
* them surface bounded diagnostic fields for telemetry); anything else → 0.
|
|
263
|
+
* Single source of truth for exit-code normalization on both traceCommand paths.
|
|
264
|
+
* @param {unknown} result
|
|
265
|
+
* @returns {number}
|
|
266
|
+
*/
|
|
267
|
+
function normalizeExitCode(result) {
|
|
268
|
+
if (result !== null && typeof result === 'object') return result.exitCode ?? 0;
|
|
269
|
+
return result ?? 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
258
272
|
/**
|
|
259
273
|
* Time a human-facing command, record its outcome, and export one span + one
|
|
260
274
|
* counter point. Returns the command's exit code unchanged. Telemetry failures
|
|
@@ -273,15 +287,33 @@ export async function traceCommand(command, args, version, run) {
|
|
|
273
287
|
config = { enabled: false };
|
|
274
288
|
}
|
|
275
289
|
|
|
276
|
-
// Fast path: no export configured → run with zero overhead.
|
|
277
|
-
|
|
290
|
+
// Fast path: no export configured → run with zero telemetry overhead. Still
|
|
291
|
+
// normalize the result to a numeric exit code: commands may resolve to an
|
|
292
|
+
// { exitCode, ...extra } object (e.g. `doctor`), and only the instrumented
|
|
293
|
+
// path below unwraps it. Returning `run()` raw would leak that object all the
|
|
294
|
+
// way to `process.exit(obj)` in the bin entry → ERR_INVALID_ARG_TYPE crash
|
|
295
|
+
// (exit 1) for every user without an OTLP endpoint configured.
|
|
296
|
+
if (!config.enabled) return normalizeExitCode(await run());
|
|
278
297
|
|
|
279
298
|
const startMs = Date.now();
|
|
280
299
|
let exitCode = 0;
|
|
281
300
|
let status = 'ok';
|
|
282
301
|
let statusMessage;
|
|
302
|
+
let extraAttrs = {};
|
|
283
303
|
try {
|
|
284
|
-
|
|
304
|
+
const result = await run();
|
|
305
|
+
// Commands may return either a plain exit code (number) or an object with
|
|
306
|
+
// { exitCode, ...extra } — the latter lets commands surface bounded,
|
|
307
|
+
// non-PII diagnostic fields (e.g. which checks failed in `doctor`).
|
|
308
|
+
exitCode = normalizeExitCode(result);
|
|
309
|
+
if (result !== null && typeof result === 'object') {
|
|
310
|
+
const { exitCode: _ec, ...rest } = result;
|
|
311
|
+
// Flatten any array-valued extras to a comma-joined string so they fit
|
|
312
|
+
// the flat attribute bag shape (OTLP stringValue).
|
|
313
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
314
|
+
extraAttrs[k] = Array.isArray(v) ? v.join(',') : v;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
285
317
|
if (typeof exitCode === 'number' && exitCode !== 0) {
|
|
286
318
|
status = 'error';
|
|
287
319
|
statusMessage = `exit ${exitCode}`;
|
|
@@ -308,6 +340,7 @@ export async function traceCommand(command, args, version, run) {
|
|
|
308
340
|
args,
|
|
309
341
|
outcome: status === 'error' ? 'error' : 'ok',
|
|
310
342
|
exitCode: typeof exitCode === 'number' ? exitCode : undefined,
|
|
343
|
+
extraAttrs,
|
|
311
344
|
});
|
|
312
345
|
await exportInvocation(config, {
|
|
313
346
|
version,
|