autotel-cli 0.8.8 → 0.8.9

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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command } from "commander";
4
+ import { Command as Command11 } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
7
  import * as fs4 from "fs";
@@ -4078,8 +4078,8 @@ async function runCodemodTrace(options) {
4078
4078
  totalWrapped += result.wrappedCount;
4079
4079
  totalChanged += 1;
4080
4080
  if (!dryRun) {
4081
- const fs7 = await import("fs");
4082
- fs7.writeFileSync(filePath, result.modified, "utf8");
4081
+ const fs9 = await import("fs");
4082
+ fs9.writeFileSync(filePath, result.modified, "utf8");
4083
4083
  }
4084
4084
  }
4085
4085
  const showSummary = printFiles || dryRun || result.changed;
@@ -4307,6 +4307,142 @@ var COMMANDS = [
4307
4307
  supportsJson: true
4308
4308
  }
4309
4309
  ];
4310
+ var INVESTIGATE_FLAGS = [
4311
+ { name: "--backend", takesValue: true, description: "Backend kind (env: AUTOTEL_BACKEND)" },
4312
+ { name: "--jaeger-base-url", takesValue: true, description: "Jaeger base URL" },
4313
+ { name: "--tempo-base-url", takesValue: true, description: "Tempo base URL" },
4314
+ { name: "--prometheus-base-url", takesValue: true, description: "Prometheus base URL" },
4315
+ { name: "--loki-base-url", takesValue: true, description: "Loki base URL" },
4316
+ { name: "--collector-port", takesValue: true, description: "OTLP receiver port" },
4317
+ { name: "--fixture-path", takesValue: true, description: "Fixture JSON path" },
4318
+ { name: "--output-file", takesValue: true, description: "Persist JSON output to this path" },
4319
+ { name: "--no-secrets-in-output", description: "Redact secret-shaped values" }
4320
+ ];
4321
+ var STATIC_FLAGS = [
4322
+ { name: "--output-file", takesValue: true, description: "Persist JSON output to this path" },
4323
+ { name: "--no-secrets-in-output", description: "Redact secret-shaped values" }
4324
+ ];
4325
+ function investigateCmd(name, description, extras = {}) {
4326
+ return {
4327
+ name,
4328
+ description,
4329
+ ...extras.args ? { args: extras.args } : {},
4330
+ flags: [...extras.static ? STATIC_FLAGS : INVESTIGATE_FLAGS, ...extras.flags ?? []],
4331
+ mutating: false,
4332
+ network: extras.network ?? !extras.static,
4333
+ writesFiles: false,
4334
+ supportsDryRun: false,
4335
+ requiresPackageJson: false,
4336
+ mayReadEnv: false,
4337
+ supportsJson: true
4338
+ };
4339
+ }
4340
+ var traceIdArg = [
4341
+ { name: "traceId", required: true, description: "Trace ID" }
4342
+ ];
4343
+ var serviceNameArg = [
4344
+ { name: "serviceName", required: true, description: "Service name" }
4345
+ ];
4346
+ var INVESTIGATE_COMMANDS = [
4347
+ investigateCmd("health", "Backend health + signal coverage"),
4348
+ investigateCmd("capabilities", "Which signals the active backend serves"),
4349
+ investigateCmd("discover", "Discover services and field shapes (parent)"),
4350
+ investigateCmd("discover services", "Services with cross-signal metadata"),
4351
+ investigateCmd("discover trace-fields", "Trace/span field names from sampled traces", {
4352
+ flags: [{ name: "--search", takesValue: true, description: "Substring filter" }]
4353
+ }),
4354
+ investigateCmd("discover log-fields", "Log field names from sampled logs", {
4355
+ flags: [{ name: "--search", takesValue: true, description: "Substring filter" }]
4356
+ }),
4357
+ investigateCmd("query", "Query traces/spans/metrics/logs (parent)"),
4358
+ investigateCmd("query traces", "Search traces by service/op/status/tags/time/error"),
4359
+ investigateCmd("query spans", "Search individual spans (extra duration filters)"),
4360
+ investigateCmd("query metrics", "List metric series"),
4361
+ investigateCmd("query logs", "Search logs"),
4362
+ investigateCmd("trace", "Trace lookup commands (parent)"),
4363
+ investigateCmd("trace get", "Get a trace by ID", { args: traceIdArg }),
4364
+ investigateCmd("trace summary", "Compact incident-friendly trace summary", { args: traceIdArg }),
4365
+ investigateCmd("topology", "Service topology commands (parent)"),
4366
+ investigateCmd("topology services", "List known services"),
4367
+ investigateCmd("topology operations", "List operations for a service", { args: serviceNameArg }),
4368
+ investigateCmd("topology map", "Service dependency map with node/edge health"),
4369
+ investigateCmd("diagnose", "Anomaly / root-cause / errors / SLO diagnosis (parent)"),
4370
+ investigateCmd("diagnose anomalies", "Latency / error-rate outliers"),
4371
+ investigateCmd("diagnose root-cause", "Bottleneck span in a trace", { args: traceIdArg }),
4372
+ investigateCmd("diagnose errors", "Error spans grouped by service/operation"),
4373
+ investigateCmd("diagnose slos", "SLO violations for a service"),
4374
+ investigateCmd("correlate", "Cross-signal correlation (parent)"),
4375
+ investigateCmd("correlate trace", "Trace + metrics + logs for a trace ID", { args: traceIdArg }),
4376
+ investigateCmd("correlate explain-slowdown", "Anomalies + root cause + correlated signals"),
4377
+ investigateCmd("llm", "LLM analytics (parent)"),
4378
+ investigateCmd("llm usage", "Token usage + USD by model and service"),
4379
+ investigateCmd("llm models", "Discover LLM models in use"),
4380
+ investigateCmd("llm model-stats", "Per-model latency/token/error stats"),
4381
+ investigateCmd("llm expensive", "Top token-spend traces"),
4382
+ investigateCmd("llm slow", "Slowest LLM traces"),
4383
+ investigateCmd("llm tools", "Tool/function spans grouped by tool name"),
4384
+ investigateCmd("semconv", "Semantic conventions lookup (parent)", { static: true }),
4385
+ investigateCmd("semconv list", "List semconv namespaces", { static: true, network: true }),
4386
+ investigateCmd("semconv get", "Groups for one namespace", {
4387
+ static: true,
4388
+ network: true,
4389
+ args: [{ name: "namespace", required: true, description: "Namespace (e.g. http)" }]
4390
+ }),
4391
+ investigateCmd("semconv refresh", "Clear semconv cache", { static: true }),
4392
+ investigateCmd("score", "Score a span for instrumentation quality (JSON on stdin)", {
4393
+ static: true,
4394
+ flags: [{ name: "--span-file", takesValue: true, description: "Read span JSON from file" }]
4395
+ }),
4396
+ investigateCmd("score explain", "Explain the instrumentation scoring rubric", { static: true }),
4397
+ investigateCmd("collector", "OpenTelemetry Collector config + schema commands (parent)", {
4398
+ static: true
4399
+ }),
4400
+ investigateCmd("collector validate", "Validate OTLP receiver config", {
4401
+ static: true,
4402
+ flags: [{ name: "--config-file", takesValue: true, description: "Read JSON config from file" }]
4403
+ }),
4404
+ investigateCmd("collector suggest", "Minimal OTLP receiver config", { static: true }),
4405
+ investigateCmd("collector explain", "Receiver config shape + defaults", { static: true }),
4406
+ investigateCmd("collector versions", "Supported collector schema versions", { static: true, network: true }),
4407
+ investigateCmd("collector components", "Components for a version", {
4408
+ static: true,
4409
+ network: true,
4410
+ flags: [
4411
+ { name: "--version", takesValue: true, description: "Collector version" },
4412
+ { name: "--kind", takesValue: true, description: "Component kind filter" }
4413
+ ]
4414
+ }),
4415
+ investigateCmd("collector schema", "JSON schema for a component", {
4416
+ static: true,
4417
+ network: true,
4418
+ flags: [
4419
+ { name: "--kind", takesValue: true, description: "Component kind" },
4420
+ { name: "--name", takesValue: true, description: "Component name" },
4421
+ { name: "--version", takesValue: true, description: "Collector version" }
4422
+ ]
4423
+ }),
4424
+ investigateCmd("collector readme", "README for a component", {
4425
+ static: true,
4426
+ network: true,
4427
+ flags: [
4428
+ { name: "--kind", takesValue: true, description: "Component kind" },
4429
+ { name: "--name", takesValue: true, description: "Component name" },
4430
+ { name: "--version", takesValue: true, description: "Collector version" }
4431
+ ]
4432
+ }),
4433
+ investigateCmd("collector validate-component", "Validate component config against upstream schema", {
4434
+ static: true,
4435
+ network: true,
4436
+ flags: [
4437
+ { name: "--kind", takesValue: true, description: "Component kind" },
4438
+ { name: "--name", takesValue: true, description: "Component name" },
4439
+ { name: "--version", takesValue: true, description: "Collector version" },
4440
+ { name: "--config-file", takesValue: true, description: "Read JSON config from file" }
4441
+ ]
4442
+ }),
4443
+ investigateCmd("collector refresh", "Refresh in-memory collector metadata cache", { static: true, network: true })
4444
+ ];
4445
+ COMMANDS.push(...INVESTIGATE_COMMANDS);
4310
4446
  function getCommand(name) {
4311
4447
  return COMMANDS.find((c) => c.name === name);
4312
4448
  }
@@ -4461,14 +4597,1199 @@ function runVersion(opts) {
4461
4597
  });
4462
4598
  }
4463
4599
 
4600
+ // src/commands/investigate/health.ts
4601
+ import { Command } from "commander";
4602
+
4603
+ // src/commands/investigate/runtime.ts
4604
+ function applyFlagsToEnv(flags) {
4605
+ if (flags.backend !== void 0) process.env.AUTOTEL_BACKEND = flags.backend;
4606
+ if (flags.jaegerBaseUrl !== void 0)
4607
+ process.env.JAEGER_BASE_URL = flags.jaegerBaseUrl;
4608
+ if (flags.tempoBaseUrl !== void 0)
4609
+ process.env.TEMPO_BASE_URL = flags.tempoBaseUrl;
4610
+ if (flags.prometheusBaseUrl !== void 0)
4611
+ process.env.PROMETHEUS_BASE_URL = flags.prometheusBaseUrl;
4612
+ if (flags.lokiBaseUrl !== void 0)
4613
+ process.env.LOKI_BASE_URL = flags.lokiBaseUrl;
4614
+ if (flags.collectorPort !== void 0)
4615
+ process.env.AUTOTEL_COLLECTOR_PORT = String(flags.collectorPort);
4616
+ if (flags.fixturePath !== void 0)
4617
+ process.env.AUTOTEL_FIXTURE_PATH = flags.fixturePath;
4618
+ }
4619
+ async function openBackend(flags) {
4620
+ applyFlagsToEnv(flags);
4621
+ const { loadConfig, createBackend } = await import("autotel-mcp");
4622
+ const config = loadConfig();
4623
+ return createBackend(config);
4624
+ }
4625
+ async function runStatic(command, flags, fn) {
4626
+ configureJsonOutput({
4627
+ outputFile: flags.outputFile,
4628
+ noSecrets: flags.noSecrets
4629
+ });
4630
+ try {
4631
+ const data = await fn();
4632
+ printJson({ ok: true, command, data });
4633
+ } catch (error2) {
4634
+ throw toInvestigateError(command, error2);
4635
+ }
4636
+ }
4637
+ async function runInvestigate(command, flags, fn) {
4638
+ configureJsonOutput({
4639
+ outputFile: flags.outputFile,
4640
+ noSecrets: flags.noSecrets
4641
+ });
4642
+ let handle = null;
4643
+ try {
4644
+ handle = await openBackend(flags);
4645
+ await handle.start();
4646
+ const data = await fn(handle.backend);
4647
+ printJson({ ok: true, command, data });
4648
+ } catch (error2) {
4649
+ throw toInvestigateError(command, error2);
4650
+ } finally {
4651
+ if (handle) {
4652
+ try {
4653
+ await handle.stop();
4654
+ } catch {
4655
+ }
4656
+ }
4657
+ }
4658
+ }
4659
+ function toInvestigateError(command, error2) {
4660
+ if (error2 instanceof AutotelError) return error2;
4661
+ if (error2 !== null && typeof error2 === "object" && "issues" in error2 && Array.isArray(error2.issues)) {
4662
+ const issues = error2.issues;
4663
+ const first = issues[0];
4664
+ const path15 = first?.path?.join(".") ?? "";
4665
+ return new AutotelError({
4666
+ type: "validation",
4667
+ code: "AUTOTEL_E_INVALID_INPUT",
4668
+ message: `autotel ${command}: invalid input${path15 ? ` for "${path15}"` : ""} \u2014 ${first?.message ?? "validation failed"}`,
4669
+ retryable: false,
4670
+ expected: { issues }
4671
+ });
4672
+ }
4673
+ const message = error2 instanceof Error ? error2.message : String(error2);
4674
+ return new AutotelError({
4675
+ type: "runtime",
4676
+ code: "AUTOTEL_E_UNKNOWN",
4677
+ message: `autotel ${command} failed: ${message}`,
4678
+ retryable: false
4679
+ });
4680
+ }
4681
+
4682
+ // src/commands/investigate/cli-helpers.ts
4683
+ var intArg = (v) => Number.parseInt(v, 10);
4684
+ var floatArg = (v) => Number.parseFloat(v);
4685
+ function addBackendFlags(cmd) {
4686
+ return cmd.option(
4687
+ "--backend <kind>",
4688
+ "Backend: collector|jaeger|tempo|prometheus|loki|stack|auto|fixture (env: AUTOTEL_BACKEND)"
4689
+ ).option("--jaeger-base-url <url>", "Jaeger base URL (env: JAEGER_BASE_URL)").option("--tempo-base-url <url>", "Tempo base URL (env: TEMPO_BASE_URL)").option(
4690
+ "--prometheus-base-url <url>",
4691
+ "Prometheus base URL (env: PROMETHEUS_BASE_URL)"
4692
+ ).option("--loki-base-url <url>", "Loki base URL (env: LOKI_BASE_URL)").option(
4693
+ "--collector-port <n>",
4694
+ "OTLP receiver port for the collector backend",
4695
+ intArg
4696
+ ).option("--fixture-path <path>", "Fixture JSON for the fixture backend").option("--output-file <path>", "Persist JSON output to this file").option("--no-secrets-in-output", "Redact secret-shaped values");
4697
+ }
4698
+ function addStaticFlags(cmd) {
4699
+ return cmd.option("--output-file <path>", "Persist JSON output to this file").option("--no-secrets-in-output", "Redact secret-shaped values");
4700
+ }
4701
+ function backendFlagsFromOpts(opts) {
4702
+ return {
4703
+ backend: opts.backend,
4704
+ jaegerBaseUrl: opts.jaegerBaseUrl,
4705
+ tempoBaseUrl: opts.tempoBaseUrl,
4706
+ prometheusBaseUrl: opts.prometheusBaseUrl,
4707
+ lokiBaseUrl: opts.lokiBaseUrl,
4708
+ collectorPort: opts.collectorPort,
4709
+ fixturePath: opts.fixturePath,
4710
+ outputFile: opts.outputFile,
4711
+ noSecrets: opts.secretsInOutput === false
4712
+ };
4713
+ }
4714
+ function staticFlagsFromOpts(opts) {
4715
+ return {
4716
+ outputFile: opts.outputFile,
4717
+ noSecrets: opts.secretsInOutput === false
4718
+ };
4719
+ }
4720
+ function addTimeWindowFlags(cmd) {
4721
+ return cmd.option("--service-name <name>", "Filter by service name").option("--operation-name <name>", "Filter by operation name").option("--lookback-minutes <n>", "Lookback window in minutes", intArg).option("--from <iso>", "Start time (ISO 8601)").option("--to <iso>", "End time (ISO 8601)").option("--limit <n>", "Max results", intArg);
4722
+ }
4723
+
4724
+ // src/commands/investigate/health.ts
4725
+ async function runHealth(flags) {
4726
+ await runInvestigate("health", flags, async (backend) => {
4727
+ const [health, capabilities] = await Promise.all([
4728
+ backend.healthCheck(),
4729
+ Promise.resolve(backend.capabilities())
4730
+ ]);
4731
+ return { ...health, signals: capabilities };
4732
+ });
4733
+ }
4734
+ async function runCapabilities(flags) {
4735
+ await runInvestigate(
4736
+ "capabilities",
4737
+ flags,
4738
+ async (backend) => backend.capabilities()
4739
+ );
4740
+ }
4741
+ function registerHealthCommands(program) {
4742
+ const healthCmd = new Command("health").description("Backend health check + signal coverage (JSON)").action(async function() {
4743
+ await runHealth(backendFlagsFromOpts(this.opts()));
4744
+ });
4745
+ addBackendFlags(healthCmd);
4746
+ program.addCommand(healthCmd);
4747
+ const capabilitiesCmd = new Command("capabilities").description("Which telemetry signals the active backend can serve (JSON)").action(async function() {
4748
+ await runCapabilities(backendFlagsFromOpts(this.opts()));
4749
+ });
4750
+ addBackendFlags(capabilitiesCmd);
4751
+ program.addCommand(capabilitiesCmd);
4752
+ }
4753
+
4754
+ // src/commands/investigate/discovery.ts
4755
+ import { Command as Command2 } from "commander";
4756
+ import {
4757
+ discoverServices,
4758
+ discoverTraceFields,
4759
+ discoverLogFields
4760
+ } from "autotel-mcp";
4761
+ async function runDiscoverServices(flags) {
4762
+ await runInvestigate("discover services", flags, async (backend) => {
4763
+ const limitServices = flags.limitServices ?? 100;
4764
+ const traceSample = flags.traceSample ?? 200;
4765
+ const logSample = flags.logSample ?? 200;
4766
+ const metricSample = flags.metricSample ?? 200;
4767
+ const caps = backend.capabilities();
4768
+ const servicesResult = await backend.listServices({ limit: limitServices });
4769
+ const services = servicesResult.services.slice(0, limitServices);
4770
+ const [traces, logs, metrics] = await Promise.all([
4771
+ caps.traces === "available" ? backend.searchTraces({ limit: traceSample }).then((r) => r.items) : Promise.resolve([]),
4772
+ caps.logs === "available" ? backend.searchLogs({ limit: logSample }).then((r) => r.items) : Promise.resolve([]),
4773
+ caps.metrics === "available" ? backend.listMetrics({ limit: metricSample }).then((r) => r.items) : Promise.resolve([])
4774
+ ]);
4775
+ const discovered = discoverServices({ services, traces, logs, metrics });
4776
+ return { count: discovered.length, services: discovered };
4777
+ });
4778
+ }
4779
+ async function runDiscoverTraceFields(flags) {
4780
+ await runInvestigate("discover trace-fields", flags, async (backend) => {
4781
+ return discoverFields(backend, flags, "traces");
4782
+ });
4783
+ }
4784
+ async function runDiscoverLogFields(flags) {
4785
+ await runInvestigate("discover log-fields", flags, async (backend) => {
4786
+ return discoverFields(backend, flags, "logs");
4787
+ });
4788
+ }
4789
+ async function discoverFields(backend, flags, signal) {
4790
+ const sampleSize = flags.sampleSize ?? 200;
4791
+ if (signal === "traces") {
4792
+ const traces = await backend.searchTraces({ limit: sampleSize }).then((r) => r.items);
4793
+ return {
4794
+ search: flags.search ?? null,
4795
+ sampleSize: traces.length,
4796
+ ...discoverTraceFields(traces, flags.search)
4797
+ };
4798
+ }
4799
+ const logs = await backend.searchLogs({ limit: sampleSize }).then((r) => r.items);
4800
+ return {
4801
+ search: flags.search ?? null,
4802
+ sampleSize: logs.length,
4803
+ ...discoverLogFields(logs, flags.search)
4804
+ };
4805
+ }
4806
+ function registerDiscoveryCommands(program) {
4807
+ const discoverCmd = new Command2("discover").description(
4808
+ "Discover services and field shapes from the active backend (JSON)"
4809
+ );
4810
+ const servicesCmd = new Command2("services").description("Discover services with cross-signal metadata").option("--limit-services <n>", "Max services", intArg).option("--trace-sample <n>", "Trace sample size", intArg).option("--log-sample <n>", "Log sample size", intArg).option("--metric-sample <n>", "Metric sample size", intArg).action(async function() {
4811
+ const o = this.optsWithGlobals();
4812
+ await runDiscoverServices({
4813
+ ...backendFlagsFromOpts(o),
4814
+ limitServices: o.limitServices,
4815
+ traceSample: o.traceSample,
4816
+ logSample: o.logSample,
4817
+ metricSample: o.metricSample
4818
+ });
4819
+ });
4820
+ const traceFieldsCmd = new Command2("trace-fields").description("Discover trace/span field names from sampled traces").option("--search <text>", "Filter field names by substring").option("--sample-size <n>", "Trace sample size", intArg).action(async function() {
4821
+ const o = this.optsWithGlobals();
4822
+ await runDiscoverTraceFields({
4823
+ ...backendFlagsFromOpts(o),
4824
+ search: o.search,
4825
+ sampleSize: o.sampleSize
4826
+ });
4827
+ });
4828
+ const logFieldsCmd = new Command2("log-fields").description("Discover log field names from sampled logs").option("--search <text>", "Filter field names by substring").option("--sample-size <n>", "Log sample size", intArg).action(async function() {
4829
+ const o = this.optsWithGlobals();
4830
+ await runDiscoverLogFields({
4831
+ ...backendFlagsFromOpts(o),
4832
+ search: o.search,
4833
+ sampleSize: o.sampleSize
4834
+ });
4835
+ });
4836
+ addBackendFlags(discoverCmd);
4837
+ discoverCmd.addCommand(servicesCmd);
4838
+ discoverCmd.addCommand(traceFieldsCmd);
4839
+ discoverCmd.addCommand(logFieldsCmd);
4840
+ program.addCommand(discoverCmd);
4841
+ }
4842
+
4843
+ // src/commands/investigate/investigation.ts
4844
+ import { Command as Command3 } from "commander";
4845
+ import {
4846
+ toTraceSearchQuery,
4847
+ toSpanSearchQuery
4848
+ } from "autotel-mcp";
4849
+
4850
+ // src/commands/investigate/signals.ts
4851
+ import {
4852
+ toMetricSearchQuery,
4853
+ toLogSearchQuery
4854
+ } from "autotel-mcp";
4855
+ async function runQueryMetrics(flags) {
4856
+ await runInvestigate(
4857
+ "query metrics",
4858
+ flags,
4859
+ async (backend) => backend.listMetrics(toMetricSearchQuery(flags))
4860
+ );
4861
+ }
4862
+ async function runQueryLogs(flags) {
4863
+ await runInvestigate(
4864
+ "query logs",
4865
+ flags,
4866
+ async (backend) => backend.searchLogs(toLogSearchQuery(flags))
4867
+ );
4868
+ }
4869
+
4870
+ // src/commands/investigate/investigation.ts
4871
+ async function runQueryTraces(flags) {
4872
+ await runInvestigate(
4873
+ "query traces",
4874
+ flags,
4875
+ async (backend) => backend.searchTraces(toTraceSearchQuery(flags))
4876
+ );
4877
+ }
4878
+ async function runQuerySpans(flags) {
4879
+ await runInvestigate(
4880
+ "query spans",
4881
+ flags,
4882
+ async (backend) => backend.searchSpans(toSpanSearchQuery(flags))
4883
+ );
4884
+ }
4885
+ async function runTraceGet(flags) {
4886
+ await runInvestigate(
4887
+ "trace get",
4888
+ flags,
4889
+ async (backend) => backend.getTrace(flags.traceId)
4890
+ );
4891
+ }
4892
+ async function runTraceSummary(flags) {
4893
+ await runInvestigate(
4894
+ "trace summary",
4895
+ flags,
4896
+ async (backend) => backend.summarizeTrace(flags.traceId)
4897
+ );
4898
+ }
4899
+ function registerQueryCommands(program) {
4900
+ const queryCmd = new Command3("query").description(
4901
+ "Query traces, spans, metrics, or logs (JSON)"
4902
+ );
4903
+ const tracesCmd = addTimeWindowFlags(new Command3("traces")).description("Search traces by service, op, status, tags, time, error").option("--error-only", "Only traces with errors").option("--status-code <code>", "OK | ERROR | UNSET").option("--min-duration-ms <n>", "Minimum duration", intArg).option("--max-duration-ms <n>", "Maximum duration", intArg).option("--gen-ai-system <name>", "gen_ai.system").option("--gen-ai-request-model <name>", "gen_ai.request.model").option("--gen-ai-response-model <name>", "gen_ai.response.model").action(async function() {
4904
+ const o = this.optsWithGlobals();
4905
+ await runQueryTraces({
4906
+ ...backendFlagsFromOpts(o),
4907
+ serviceName: o.serviceName,
4908
+ operationName: o.operationName,
4909
+ lookbackMinutes: o.lookbackMinutes,
4910
+ from: o.from,
4911
+ to: o.to,
4912
+ limit: o.limit,
4913
+ errorOnly: o.errorOnly,
4914
+ statusCode: o.statusCode,
4915
+ minDurationMs: o.minDurationMs,
4916
+ maxDurationMs: o.maxDurationMs,
4917
+ genAiSystem: o.genAiSystem,
4918
+ genAiRequestModel: o.genAiRequestModel,
4919
+ genAiResponseModel: o.genAiResponseModel
4920
+ });
4921
+ });
4922
+ const spansCmd = addTimeWindowFlags(new Command3("spans")).description("Search individual spans by service/op/status/tags/duration").option("--error-only", "Only spans with errors").option("--status-code <code>", "OK | ERROR | UNSET").option("--min-duration-ms <n>", "Minimum span duration", intArg).option("--max-duration-ms <n>", "Maximum span duration", intArg).action(async function() {
4923
+ const o = this.optsWithGlobals();
4924
+ await runQuerySpans({
4925
+ ...backendFlagsFromOpts(o),
4926
+ serviceName: o.serviceName,
4927
+ operationName: o.operationName,
4928
+ lookbackMinutes: o.lookbackMinutes,
4929
+ from: o.from,
4930
+ to: o.to,
4931
+ limit: o.limit,
4932
+ errorOnly: o.errorOnly,
4933
+ statusCode: o.statusCode,
4934
+ minDurationMs: o.minDurationMs,
4935
+ maxDurationMs: o.maxDurationMs
4936
+ });
4937
+ });
4938
+ const metricsCmd = addTimeWindowFlags(new Command3("metrics")).description("List metric series").option("--metric-name <name>", "Filter by metric name").action(async function() {
4939
+ const o = this.optsWithGlobals();
4940
+ await runQueryMetrics({
4941
+ ...backendFlagsFromOpts(o),
4942
+ metricName: o.metricName,
4943
+ serviceName: o.serviceName,
4944
+ lookbackMinutes: o.lookbackMinutes,
4945
+ from: o.from,
4946
+ to: o.to,
4947
+ limit: o.limit
4948
+ });
4949
+ });
4950
+ const logsCmd = addTimeWindowFlags(new Command3("logs")).description("Search logs").option("--trace-id <id>", "Filter by trace id").option("--span-id <id>", "Filter by span id").option("--severity-text <text>", "Severity text").option("--text <text>", "Free-text search").action(async function() {
4951
+ const o = this.optsWithGlobals();
4952
+ await runQueryLogs({
4953
+ ...backendFlagsFromOpts(o),
4954
+ serviceName: o.serviceName,
4955
+ traceId: o.traceId,
4956
+ spanId: o.spanId,
4957
+ severityText: o.severityText,
4958
+ text: o.text,
4959
+ lookbackMinutes: o.lookbackMinutes,
4960
+ from: o.from,
4961
+ to: o.to,
4962
+ limit: o.limit
4963
+ });
4964
+ });
4965
+ addBackendFlags(queryCmd);
4966
+ queryCmd.addCommand(tracesCmd);
4967
+ queryCmd.addCommand(spansCmd);
4968
+ queryCmd.addCommand(metricsCmd);
4969
+ queryCmd.addCommand(logsCmd);
4970
+ program.addCommand(queryCmd);
4971
+ }
4972
+ function registerTraceCommands(program) {
4973
+ const traceLookupCmd = new Command3("trace").description(
4974
+ "Trace lookup commands (JSON)"
4975
+ );
4976
+ const getCmd = new Command3("get").description("Get a trace by ID").argument("<traceId>", "Trace ID").action(async function(traceId) {
4977
+ await runTraceGet({
4978
+ ...backendFlagsFromOpts(this.optsWithGlobals()),
4979
+ traceId
4980
+ });
4981
+ });
4982
+ const summaryCmd = new Command3("summary").description("Compact incident-friendly trace summary").argument("<traceId>", "Trace ID").action(async function(traceId) {
4983
+ await runTraceSummary({
4984
+ ...backendFlagsFromOpts(this.optsWithGlobals()),
4985
+ traceId
4986
+ });
4987
+ });
4988
+ addBackendFlags(traceLookupCmd);
4989
+ traceLookupCmd.addCommand(getCmd);
4990
+ traceLookupCmd.addCommand(summaryCmd);
4991
+ program.addCommand(traceLookupCmd);
4992
+ }
4993
+
4994
+ // src/commands/investigate/topology.ts
4995
+ import { Command as Command4 } from "commander";
4996
+ async function runListServices(flags) {
4997
+ await runInvestigate(
4998
+ "topology services",
4999
+ flags,
5000
+ async (backend) => backend.listServices()
5001
+ );
5002
+ }
5003
+ async function runListOperations(flags) {
5004
+ await runInvestigate(
5005
+ "topology operations",
5006
+ flags,
5007
+ async (backend) => backend.listOperations(flags.serviceName)
5008
+ );
5009
+ }
5010
+ async function runServiceMap(flags) {
5011
+ await runInvestigate(
5012
+ "topology map",
5013
+ flags,
5014
+ async (backend) => backend.serviceMap(flags.lookbackMinutes ?? 60, flags.limit ?? 20)
5015
+ );
5016
+ }
5017
+ function registerTopologyCommands(program) {
5018
+ const topologyCmd = new Command4("topology").description(
5019
+ "Service topology commands (JSON)"
5020
+ );
5021
+ const servicesCmd = new Command4("services").description("List known services").action(async function() {
5022
+ await runListServices(backendFlagsFromOpts(this.optsWithGlobals()));
5023
+ });
5024
+ const operationsCmd = new Command4("operations").description("List operations for a service").argument("<serviceName>", "Service name").action(async function(serviceName) {
5025
+ await runListOperations({
5026
+ ...backendFlagsFromOpts(this.optsWithGlobals()),
5027
+ serviceName
5028
+ });
5029
+ });
5030
+ const mapCmd = new Command4("map").description("Build a service dependency map").option("--lookback-minutes <n>", "Lookback in minutes", intArg).option("--limit <n>", "Max services", intArg).action(async function() {
5031
+ const o = this.optsWithGlobals();
5032
+ await runServiceMap({
5033
+ ...backendFlagsFromOpts(o),
5034
+ lookbackMinutes: o.lookbackMinutes,
5035
+ limit: o.limit
5036
+ });
5037
+ });
5038
+ addBackendFlags(topologyCmd);
5039
+ topologyCmd.addCommand(servicesCmd);
5040
+ topologyCmd.addCommand(operationsCmd);
5041
+ topologyCmd.addCommand(mapCmd);
5042
+ program.addCommand(topologyCmd);
5043
+ }
5044
+
5045
+ // src/commands/investigate/diagnosis.ts
5046
+ import { Command as Command5 } from "commander";
5047
+ import {
5048
+ detectAnomalies,
5049
+ findRootCause,
5050
+ pickErrorMessage
5051
+ } from "autotel-mcp";
5052
+ async function runDiagnoseAnomalies(flags) {
5053
+ await runInvestigate("diagnose anomalies", flags, async (backend) => {
5054
+ const lookback = flags.lookbackMinutes ?? 60;
5055
+ const nowMs = Date.now();
5056
+ const result = await backend.searchTraces({
5057
+ service: flags.service,
5058
+ startTimeUnixMs: nowMs - lookback * 60 * 1e3,
5059
+ endTimeUnixMs: nowMs,
5060
+ limit: 100
5061
+ });
5062
+ return detectAnomalies(result.items, {
5063
+ service: flags.service,
5064
+ operation: flags.operation
5065
+ });
5066
+ });
5067
+ }
5068
+ async function runDiagnoseRootCause(flags) {
5069
+ await runInvestigate("diagnose root-cause", flags, async (backend) => {
5070
+ const trace = await backend.getTrace(flags.traceId);
5071
+ if (!trace) return { error: `Trace not found: ${flags.traceId}` };
5072
+ return findRootCause(trace);
5073
+ });
5074
+ }
5075
+ async function runDiagnoseErrors(flags) {
5076
+ await runInvestigate("diagnose errors", flags, async (backend) => {
5077
+ const lookback = flags.lookbackMinutes ?? 60;
5078
+ const limit = flags.limit ?? 20;
5079
+ const nowMs = Date.now();
5080
+ const result = await backend.searchTraces({
5081
+ service: flags.service,
5082
+ hasError: true,
5083
+ startTimeUnixMs: nowMs - lookback * 60 * 1e3,
5084
+ endTimeUnixMs: nowMs,
5085
+ limit
5086
+ });
5087
+ const groups = /* @__PURE__ */ new Map();
5088
+ for (const trace of result.items) {
5089
+ for (const span of trace.spans) {
5090
+ if (!span.hasError) continue;
5091
+ if (flags.service && span.serviceName !== flags.service) continue;
5092
+ const key = `${span.serviceName}::${span.operationName}`;
5093
+ if (!groups.has(key)) {
5094
+ groups.set(key, {
5095
+ service: span.serviceName,
5096
+ operation: span.operationName,
5097
+ count: 0,
5098
+ errorMessages: [],
5099
+ traceIds: []
5100
+ });
5101
+ }
5102
+ const group = groups.get(key);
5103
+ group.count++;
5104
+ const msg = pickErrorMessage(span.tags);
5105
+ if (msg && !group.errorMessages.includes(msg)) {
5106
+ group.errorMessages.push(msg);
5107
+ }
5108
+ if (!group.traceIds.includes(trace.traceId)) {
5109
+ group.traceIds.push(trace.traceId);
5110
+ }
5111
+ }
5112
+ }
5113
+ return {
5114
+ totalTraces: result.totalCount,
5115
+ groups: [...groups.values()].toSorted((a, b) => b.count - a.count)
5116
+ };
5117
+ });
5118
+ }
5119
+ async function runDiagnoseSlos(flags) {
5120
+ await runInvestigate("diagnose slos", flags, async (backend) => {
5121
+ const lookback = flags.lookbackMinutes ?? 60;
5122
+ const nowMs = Date.now();
5123
+ const result = await backend.searchTraces({
5124
+ service: flags.service,
5125
+ startTimeUnixMs: nowMs - lookback * 60 * 1e3,
5126
+ endTimeUnixMs: nowMs,
5127
+ limit: 100
5128
+ });
5129
+ const spans = result.items.flatMap(
5130
+ (t) => t.spans.filter((s) => s.serviceName === flags.service)
5131
+ );
5132
+ const violations = [];
5133
+ if (spans.length === 0) {
5134
+ return {
5135
+ service: flags.service,
5136
+ totalSpans: 0,
5137
+ violations,
5138
+ message: "No spans found for the given service and time window."
5139
+ };
5140
+ }
5141
+ const durations = spans.map((s) => s.durationMs).toSorted((a, b) => a - b);
5142
+ const p99Index = Math.floor(durations.length * 0.99);
5143
+ const actualP99 = durations[Math.min(p99Index, durations.length - 1)];
5144
+ if (flags.p99LatencyMs !== void 0 && actualP99 > flags.p99LatencyMs) {
5145
+ violations.push({
5146
+ type: "p99_latency",
5147
+ target: flags.p99LatencyMs,
5148
+ actual: actualP99,
5149
+ description: `p99 latency ${actualP99.toFixed(1)}ms exceeds target ${flags.p99LatencyMs}ms`
5150
+ });
5151
+ }
5152
+ const errorCount = spans.filter((s) => s.hasError).length;
5153
+ const actualErrorRate = errorCount / spans.length;
5154
+ if (flags.maxErrorRate !== void 0 && actualErrorRate > flags.maxErrorRate) {
5155
+ violations.push({
5156
+ type: "error_rate",
5157
+ target: flags.maxErrorRate,
5158
+ actual: actualErrorRate,
5159
+ description: `Error rate ${(actualErrorRate * 100).toFixed(2)}% exceeds target ${(flags.maxErrorRate * 100).toFixed(2)}%`
5160
+ });
5161
+ }
5162
+ return {
5163
+ service: flags.service,
5164
+ totalSpans: spans.length,
5165
+ p99LatencyMs: actualP99,
5166
+ errorRate: actualErrorRate,
5167
+ violations
5168
+ };
5169
+ });
5170
+ }
5171
+ function registerDiagnoseCommands(program) {
5172
+ const diagnoseCmd = new Command5("diagnose").description(
5173
+ "Anomaly / root-cause / errors / SLO diagnosis (JSON)"
5174
+ );
5175
+ const anomaliesCmd = new Command5("anomalies").description("Detect latency/error-rate outliers").option("--service <name>", "Service filter").option("--operation <name>", "Operation filter").option("--lookback-minutes <n>", "Lookback in minutes", intArg).action(async function() {
5176
+ const o = this.optsWithGlobals();
5177
+ await runDiagnoseAnomalies({
5178
+ ...backendFlagsFromOpts(o),
5179
+ service: o.service,
5180
+ operation: o.operation,
5181
+ lookbackMinutes: o.lookbackMinutes
5182
+ });
5183
+ });
5184
+ const rootCauseCmd = new Command5("root-cause").description("Walk a trace tree to identify the bottleneck span").argument("<traceId>", "Trace ID").action(async function(traceId) {
5185
+ await runDiagnoseRootCause({
5186
+ ...backendFlagsFromOpts(this.optsWithGlobals()),
5187
+ traceId
5188
+ });
5189
+ });
5190
+ const errorsCmd = new Command5("errors").description("Aggregate error spans by service/operation").option("--service <name>", "Service filter").option("--lookback-minutes <n>", "Lookback in minutes", intArg).option("--limit <n>", "Max traces to scan", intArg).action(async function() {
5191
+ const o = this.optsWithGlobals();
5192
+ await runDiagnoseErrors({
5193
+ ...backendFlagsFromOpts(o),
5194
+ service: o.service,
5195
+ lookbackMinutes: o.lookbackMinutes,
5196
+ limit: o.limit
5197
+ });
5198
+ });
5199
+ const slosCmd = new Command5("slos").description("Report SLO violations for a service").requiredOption("--service <name>", "Service to check").option("--p99-latency-ms <n>", "p99 latency target", floatArg).option("--max-error-rate <n>", "Error-rate target (0..1)", floatArg).option("--lookback-minutes <n>", "Lookback in minutes", intArg).action(async function() {
5200
+ const o = this.optsWithGlobals();
5201
+ await runDiagnoseSlos({
5202
+ ...backendFlagsFromOpts(o),
5203
+ service: o.service,
5204
+ p99LatencyMs: o.p99LatencyMs,
5205
+ maxErrorRate: o.maxErrorRate,
5206
+ lookbackMinutes: o.lookbackMinutes
5207
+ });
5208
+ });
5209
+ addBackendFlags(diagnoseCmd);
5210
+ diagnoseCmd.addCommand(anomaliesCmd);
5211
+ diagnoseCmd.addCommand(rootCauseCmd);
5212
+ diagnoseCmd.addCommand(errorsCmd);
5213
+ diagnoseCmd.addCommand(slosCmd);
5214
+ program.addCommand(diagnoseCmd);
5215
+ }
5216
+
5217
+ // src/commands/investigate/correlation.ts
5218
+ import { Command as Command6 } from "commander";
5219
+ import { detectAnomalies as detectAnomalies2, findRootCause as findRootCause2 } from "autotel-mcp";
5220
+ async function runCorrelate(flags) {
5221
+ await runInvestigate(
5222
+ "correlate trace",
5223
+ flags,
5224
+ async (backend) => backend.getCorrelatedSignals(flags.traceId)
5225
+ );
5226
+ }
5227
+ async function runExplainSlowdown(flags) {
5228
+ await runInvestigate("correlate explain-slowdown", flags, async (backend) => {
5229
+ const lookback = flags.lookbackMinutes ?? 60;
5230
+ const nowMs = Date.now();
5231
+ const result = await backend.searchTraces({
5232
+ service: flags.service,
5233
+ startTimeUnixMs: nowMs - lookback * 60 * 1e3,
5234
+ endTimeUnixMs: nowMs,
5235
+ limit: 100
5236
+ });
5237
+ const anomalies = detectAnomalies2(result.items, { service: flags.service });
5238
+ const findings = await Promise.all(
5239
+ anomalies.map(async (anomaly) => {
5240
+ const sampleTraceId = anomaly.affectedTraceIds[0];
5241
+ if (!sampleTraceId) {
5242
+ return { anomaly, rootCause: null, correlatedSignals: null };
5243
+ }
5244
+ const trace = await backend.getTrace(sampleTraceId);
5245
+ const rootCause = trace ? findRootCause2(trace) : null;
5246
+ const correlatedSignals = await backend.getCorrelatedSignals(sampleTraceId);
5247
+ return { anomaly, rootCause, correlatedSignals };
5248
+ })
5249
+ );
5250
+ return {
5251
+ service: flags.service,
5252
+ lookbackMinutes: lookback,
5253
+ anomalyCount: anomalies.length,
5254
+ findings
5255
+ };
5256
+ });
5257
+ }
5258
+ function registerCorrelateCommands(program) {
5259
+ const correlateCmd = new Command6("correlate").description(
5260
+ "Cross-signal correlation (JSON)"
5261
+ );
5262
+ const traceCmd = new Command6("trace").description("Trace + metrics + correlated logs for a trace ID").argument("<traceId>", "Trace ID").action(async function(traceId) {
5263
+ await runCorrelate({
5264
+ ...backendFlagsFromOpts(this.optsWithGlobals()),
5265
+ traceId
5266
+ });
5267
+ });
5268
+ const slowdownCmd = new Command6("explain-slowdown").description("Identify when/why a service degraded").requiredOption("--service <name>", "Service name").option("--lookback-minutes <n>", "Lookback in minutes", intArg).action(async function() {
5269
+ const o = this.optsWithGlobals();
5270
+ await runExplainSlowdown({
5271
+ ...backendFlagsFromOpts(o),
5272
+ service: o.service,
5273
+ lookbackMinutes: o.lookbackMinutes
5274
+ });
5275
+ });
5276
+ addBackendFlags(correlateCmd);
5277
+ correlateCmd.addCommand(traceCmd);
5278
+ correlateCmd.addCommand(slowdownCmd);
5279
+ program.addCommand(correlateCmd);
5280
+ }
5281
+
5282
+ // src/commands/investigate/llm.ts
5283
+ import {
5284
+ collectUsage,
5285
+ listModels,
5286
+ getModelStats,
5287
+ rankExpensiveTraces,
5288
+ rankSlowTraces,
5289
+ listToolUsage,
5290
+ toTraceSearchQuery as toTraceSearchQuery2
5291
+ } from "autotel-mcp";
5292
+ import { Command as Command7 } from "commander";
5293
+ function parseDateToUnixMs(value) {
5294
+ if (!value) return void 0;
5295
+ const parsed = Date.parse(value);
5296
+ return Number.isFinite(parsed) ? parsed : void 0;
5297
+ }
5298
+ async function collectTracesForAnalytics(backend, input2) {
5299
+ const result = await backend.searchTraces(
5300
+ toTraceSearchQuery2({
5301
+ serviceName: input2.serviceName,
5302
+ genAiSystem: input2.genAiSystem,
5303
+ genAiRequestModel: input2.genAiRequestModel,
5304
+ genAiResponseModel: input2.genAiResponseModel,
5305
+ limit: input2.limit ?? 1e3
5306
+ })
5307
+ );
5308
+ let filtered = result.items;
5309
+ const startUnixMs = parseDateToUnixMs(input2.startTime);
5310
+ const endUnixMs = parseDateToUnixMs(input2.endTime);
5311
+ if (startUnixMs !== void 0) {
5312
+ filtered = filtered.filter(
5313
+ (trace) => trace.spans.some((span) => span.startTimeUnixMs >= startUnixMs)
5314
+ );
5315
+ }
5316
+ if (endUnixMs !== void 0) {
5317
+ filtered = filtered.filter(
5318
+ (trace) => trace.spans.some((span) => span.startTimeUnixMs <= endUnixMs)
5319
+ );
5320
+ }
5321
+ return filtered;
5322
+ }
5323
+ async function runLlmUsage(flags) {
5324
+ await runInvestigate("llm usage", flags, async (backend) => {
5325
+ const traces = await collectTracesForAnalytics(backend, flags);
5326
+ const report = collectUsage(traces);
5327
+ return {
5328
+ period: {
5329
+ startTime: flags.startTime ?? null,
5330
+ endTime: flags.endTime ?? null
5331
+ },
5332
+ filters: {
5333
+ serviceName: flags.serviceName ?? null,
5334
+ genAiSystem: flags.genAiSystem ?? null,
5335
+ genAiRequestModel: flags.genAiRequestModel ?? null,
5336
+ genAiResponseModel: flags.genAiResponseModel ?? null
5337
+ },
5338
+ summary: {
5339
+ totalRequests: report.totalRequests,
5340
+ totalPromptTokens: report.totalPromptTokens,
5341
+ totalCompletionTokens: report.totalCompletionTokens,
5342
+ totalTokens: report.totalTokens,
5343
+ totalCostUsd: report.totalCostUsd,
5344
+ unpricedRequests: report.unpricedRequests
5345
+ },
5346
+ byModel: report.byModel,
5347
+ byService: report.byService
5348
+ };
5349
+ });
5350
+ }
5351
+ async function runLlmModels(flags) {
5352
+ await runInvestigate("llm models", flags, async (backend) => {
5353
+ const traces = await collectTracesForAnalytics(backend, flags);
5354
+ const models = listModels(traces).slice(0, flags.limit ?? 1e3);
5355
+ return { count: models.length, models };
5356
+ });
5357
+ }
5358
+ async function runLlmModelStats(flags) {
5359
+ await runInvestigate("llm model-stats", flags, async (backend) => {
5360
+ const traces = await collectTracesForAnalytics(backend, flags);
5361
+ const stats = getModelStats(traces, flags.modelName);
5362
+ if (!stats) {
5363
+ return {
5364
+ error: `No traces found for model '${flags.modelName}' in the specified time range`
5365
+ };
5366
+ }
5367
+ return stats;
5368
+ });
5369
+ }
5370
+ async function runLlmExpensive(flags) {
5371
+ await runInvestigate("llm expensive", flags, async (backend) => {
5372
+ const traces = await collectTracesForAnalytics(backend, flags);
5373
+ let ranked = rankExpensiveTraces(traces);
5374
+ if (flags.minTokens !== void 0) {
5375
+ ranked = ranked.filter((t) => t.tokens.total >= flags.minTokens);
5376
+ }
5377
+ ranked = ranked.slice(0, flags.limit ?? 10);
5378
+ return { count: ranked.length, traces: ranked };
5379
+ });
5380
+ }
5381
+ async function runLlmSlow(flags) {
5382
+ await runInvestigate("llm slow", flags, async (backend) => {
5383
+ const traces = await collectTracesForAnalytics(backend, flags);
5384
+ let ranked = rankSlowTraces(traces);
5385
+ if (flags.minDurationMs !== void 0) {
5386
+ ranked = ranked.filter((t) => t.durationMs >= flags.minDurationMs);
5387
+ }
5388
+ ranked = ranked.slice(0, flags.limit ?? 10);
5389
+ return { count: ranked.length, traces: ranked };
5390
+ });
5391
+ }
5392
+ async function runLlmTools(flags) {
5393
+ await runInvestigate("llm tools", flags, async (backend) => {
5394
+ const traces = await collectTracesForAnalytics(backend, flags);
5395
+ const tools = listToolUsage(traces).slice(0, flags.limit ?? 1e3);
5396
+ return {
5397
+ count: tools.length,
5398
+ totalCalls: tools.reduce((sum, t) => sum + t.usageCount, 0),
5399
+ tools
5400
+ };
5401
+ });
5402
+ }
5403
+ function registerLlmCommands(program) {
5404
+ const llmCmd = new Command7("llm").description(
5405
+ "LLM analytics (cost, models, expensive/slow traces, tools)"
5406
+ );
5407
+ const commonOpts = (cmd) => cmd.option("--start-time <iso>", "Start of window (ISO 8601)").option("--end-time <iso>", "End of window (ISO 8601)").option("--service-name <name>", "Service filter").option("--gen-ai-system <name>", "gen_ai.system filter").option("--gen-ai-request-model <name>", "gen_ai.request.model filter").option("--gen-ai-response-model <name>", "gen_ai.response.model filter").option("--limit <n>", "Max results", intArg);
5408
+ const usageCmd = commonOpts(new Command7("usage")).description("Aggregate token usage by model and service").action(async function() {
5409
+ const o = this.optsWithGlobals();
5410
+ await runLlmUsage({
5411
+ ...backendFlagsFromOpts(o),
5412
+ startTime: o.startTime,
5413
+ endTime: o.endTime,
5414
+ serviceName: o.serviceName,
5415
+ genAiSystem: o.genAiSystem,
5416
+ genAiRequestModel: o.genAiRequestModel,
5417
+ genAiResponseModel: o.genAiResponseModel,
5418
+ limit: o.limit
5419
+ });
5420
+ });
5421
+ const modelsCmd = commonOpts(new Command7("models")).description("Discover LLM models in use").action(async function() {
5422
+ const o = this.optsWithGlobals();
5423
+ await runLlmModels({
5424
+ ...backendFlagsFromOpts(o),
5425
+ startTime: o.startTime,
5426
+ endTime: o.endTime,
5427
+ serviceName: o.serviceName,
5428
+ genAiSystem: o.genAiSystem,
5429
+ limit: o.limit
5430
+ });
5431
+ });
5432
+ const modelStatsCmd = commonOpts(new Command7("model-stats")).description("Latency/token/error stats for one LLM model").requiredOption("--model-name <name>", "Model to inspect").action(async function() {
5433
+ const o = this.optsWithGlobals();
5434
+ await runLlmModelStats({
5435
+ ...backendFlagsFromOpts(o),
5436
+ modelName: o.modelName,
5437
+ startTime: o.startTime,
5438
+ endTime: o.endTime,
5439
+ serviceName: o.serviceName
5440
+ });
5441
+ });
5442
+ const expensiveCmd = commonOpts(new Command7("expensive")).description("Traces with highest total LLM token usage").option("--min-tokens <n>", "Minimum token threshold", intArg).action(async function() {
5443
+ const o = this.optsWithGlobals();
5444
+ await runLlmExpensive({
5445
+ ...backendFlagsFromOpts(o),
5446
+ startTime: o.startTime,
5447
+ endTime: o.endTime,
5448
+ serviceName: o.serviceName,
5449
+ genAiRequestModel: o.genAiRequestModel,
5450
+ genAiResponseModel: o.genAiResponseModel,
5451
+ minTokens: o.minTokens,
5452
+ limit: o.limit
5453
+ });
5454
+ });
5455
+ const slowCmd = commonOpts(new Command7("slow")).description("Slowest traces that include LLM spans").option("--min-duration-ms <n>", "Minimum duration", intArg).action(async function() {
5456
+ const o = this.optsWithGlobals();
5457
+ await runLlmSlow({
5458
+ ...backendFlagsFromOpts(o),
5459
+ startTime: o.startTime,
5460
+ endTime: o.endTime,
5461
+ serviceName: o.serviceName,
5462
+ genAiRequestModel: o.genAiRequestModel,
5463
+ genAiResponseModel: o.genAiResponseModel,
5464
+ minDurationMs: o.minDurationMs,
5465
+ limit: o.limit
5466
+ });
5467
+ });
5468
+ const toolsCmd = commonOpts(new Command7("tools")).description("Discover tool/function spans grouped by tool name").action(async function() {
5469
+ const o = this.optsWithGlobals();
5470
+ await runLlmTools({
5471
+ ...backendFlagsFromOpts(o),
5472
+ startTime: o.startTime,
5473
+ endTime: o.endTime,
5474
+ serviceName: o.serviceName,
5475
+ genAiSystem: o.genAiSystem,
5476
+ limit: o.limit
5477
+ });
5478
+ });
5479
+ addBackendFlags(llmCmd);
5480
+ llmCmd.addCommand(usageCmd);
5481
+ llmCmd.addCommand(modelsCmd);
5482
+ llmCmd.addCommand(modelStatsCmd);
5483
+ llmCmd.addCommand(expensiveCmd);
5484
+ llmCmd.addCommand(slowCmd);
5485
+ llmCmd.addCommand(toolsCmd);
5486
+ program.addCommand(llmCmd);
5487
+ }
5488
+
5489
+ // src/commands/investigate/semconv.ts
5490
+ import {
5491
+ clearSemanticConventionCache,
5492
+ getSemanticConventionNamespace,
5493
+ listSemanticConventionNamespaces
5494
+ } from "autotel-mcp";
5495
+ import { Command as Command8 } from "commander";
5496
+ async function runSemconvList(flags) {
5497
+ await runStatic("semconv list", flags, async () => ({
5498
+ namespaces: await listSemanticConventionNamespaces()
5499
+ }));
5500
+ }
5501
+ async function runSemconvGet(flags) {
5502
+ await runStatic(
5503
+ "semconv get",
5504
+ flags,
5505
+ async () => getSemanticConventionNamespace(flags.namespace)
5506
+ );
5507
+ }
5508
+ async function runSemconvRefresh(flags) {
5509
+ await runStatic("semconv refresh", flags, async () => {
5510
+ clearSemanticConventionCache();
5511
+ return { cleared: true };
5512
+ });
5513
+ }
5514
+ function registerSemconvCommands(program) {
5515
+ const semconvCmd = new Command8("semconv").description(
5516
+ "OpenTelemetry semantic conventions lookup (JSON)"
5517
+ );
5518
+ const listCmd = addStaticFlags(new Command8("list")).description("List semconv namespaces").action(async function() {
5519
+ await runSemconvList(staticFlagsFromOpts(this.optsWithGlobals()));
5520
+ });
5521
+ const getCmd = addStaticFlags(new Command8("get")).description("Get groups for one namespace").argument("<namespace>", "Namespace (e.g. http, rpc, database)").action(async function(namespace) {
5522
+ await runSemconvGet({
5523
+ ...staticFlagsFromOpts(this.optsWithGlobals()),
5524
+ namespace
5525
+ });
5526
+ });
5527
+ const refreshCmd = addStaticFlags(new Command8("refresh")).description("Clear semconv cache").action(async function() {
5528
+ await runSemconvRefresh(staticFlagsFromOpts(this.optsWithGlobals()));
5529
+ });
5530
+ semconvCmd.addCommand(listCmd);
5531
+ semconvCmd.addCommand(getCmd);
5532
+ semconvCmd.addCommand(refreshCmd);
5533
+ program.addCommand(semconvCmd);
5534
+ }
5535
+
5536
+ // src/commands/investigate/instrumentation.ts
5537
+ import {
5538
+ scoreSpan,
5539
+ suggestInstrumentationFixes,
5540
+ buildInstrumentationGuide
5541
+ } from "autotel-mcp";
5542
+ import { Command as Command9 } from "commander";
5543
+ import * as fs7 from "fs";
5544
+ function readSpanFromStdinOrFile(spanFile) {
5545
+ let raw;
5546
+ if (spanFile) {
5547
+ raw = fs7.readFileSync(spanFile, "utf8");
5548
+ } else {
5549
+ raw = fs7.readFileSync(0, "utf8");
5550
+ }
5551
+ const parsed = JSON.parse(raw);
5552
+ if (typeof parsed.operationName !== "string" || typeof parsed.serviceName !== "string" || typeof parsed.tags !== "object" || typeof parsed.hasError !== "boolean") {
5553
+ throw new AutotelError({
5554
+ type: "validation",
5555
+ code: "AUTOTEL_E_INVALID_INPUT",
5556
+ message: "score expects JSON with operationName, serviceName, tags, hasError",
5557
+ retryable: false,
5558
+ expected: {
5559
+ shape: {
5560
+ operationName: "string",
5561
+ serviceName: "string",
5562
+ tags: "Record<string, string | number | boolean>",
5563
+ hasError: "boolean"
5564
+ }
5565
+ }
5566
+ });
5567
+ }
5568
+ return parsed;
5569
+ }
5570
+ async function runScoreSpan(flags) {
5571
+ await runStatic("score", flags, async () => {
5572
+ const span = readSpanFromStdinOrFile(flags.spanFile);
5573
+ const result = scoreSpan(span);
5574
+ const suggestions = suggestInstrumentationFixes(span);
5575
+ return { ...result, suggestions };
5576
+ });
5577
+ }
5578
+ async function runScoreExplain(flags) {
5579
+ await runStatic("score explain", flags, async () => ({
5580
+ guide: buildInstrumentationGuide()
5581
+ }));
5582
+ }
5583
+ function registerScoreCommands(program) {
5584
+ const scoreCmd = addStaticFlags(new Command9("score")).description("Score a span for instrumentation quality (JSON)").option("--span-file <path>", "Read span JSON from file (default: stdin)").action(async function() {
5585
+ const o = this.optsWithGlobals();
5586
+ await runScoreSpan({
5587
+ ...staticFlagsFromOpts(o),
5588
+ spanFile: o.spanFile
5589
+ });
5590
+ });
5591
+ const explainCmd = addStaticFlags(new Command9("explain")).description("Explain the instrumentation scoring rubric").action(async function() {
5592
+ await runScoreExplain(staticFlagsFromOpts(this.optsWithGlobals()));
5593
+ });
5594
+ scoreCmd.addCommand(explainCmd);
5595
+ program.addCommand(scoreCmd);
5596
+ }
5597
+
5598
+ // src/commands/investigate/collector.ts
5599
+ import {
5600
+ validateOtlpReceiverConfig,
5601
+ suggestCollectorConfig,
5602
+ buildCollectorGuide,
5603
+ listCollectorVersions,
5604
+ listCollectorComponents,
5605
+ getCollectorComponentSchema,
5606
+ getCollectorComponentReadme,
5607
+ validateCollectorComponentConfig,
5608
+ refreshCollectorCatalog,
5609
+ resolveCollectorVersion
5610
+ } from "autotel-mcp";
5611
+ import { Command as Command10 } from "commander";
5612
+ import * as fs8 from "fs";
5613
+ function readJsonFromStdinOrFile(file) {
5614
+ const raw = file ? fs8.readFileSync(file, "utf8") : fs8.readFileSync(0, "utf8");
5615
+ return JSON.parse(raw);
5616
+ }
5617
+ function assertVersion(version) {
5618
+ if (version === void 0) return;
5619
+ if (!/^\d+\.\d+\.\d+$/.test(version)) {
5620
+ throw new AutotelError({
5621
+ type: "validation",
5622
+ code: "AUTOTEL_E_INVALID_INPUT",
5623
+ message: `--version must be semver (got "${version}")`,
5624
+ retryable: false
5625
+ });
5626
+ }
5627
+ }
5628
+ async function runCollectorValidate(flags) {
5629
+ await runStatic("collector validate", flags, async () => {
5630
+ const config = readJsonFromStdinOrFile(flags.configFile);
5631
+ return validateOtlpReceiverConfig(config);
5632
+ });
5633
+ }
5634
+ async function runCollectorSuggest(flags) {
5635
+ await runStatic("collector suggest", flags, async () => ({
5636
+ suggestion: suggestCollectorConfig()
5637
+ }));
5638
+ }
5639
+ async function runCollectorExplain(flags) {
5640
+ await runStatic("collector explain", flags, async () => ({
5641
+ guide: buildCollectorGuide()
5642
+ }));
5643
+ }
5644
+ async function runCollectorVersions(flags) {
5645
+ await runStatic("collector versions", flags, async () => ({
5646
+ versions: await listCollectorVersions()
5647
+ }));
5648
+ }
5649
+ async function runCollectorComponents(flags) {
5650
+ await runStatic("collector components", flags, async () => {
5651
+ assertVersion(flags.version);
5652
+ const resolvedVersion = await resolveCollectorVersion(flags.version);
5653
+ const components = await listCollectorComponents(resolvedVersion);
5654
+ if (flags.kind) {
5655
+ return {
5656
+ version: resolvedVersion,
5657
+ kind: flags.kind,
5658
+ components: components[flags.kind]
5659
+ };
5660
+ }
5661
+ return { version: resolvedVersion, components };
5662
+ });
5663
+ }
5664
+ async function runCollectorSchema(flags) {
5665
+ await runStatic("collector schema", flags, async () => {
5666
+ assertVersion(flags.version);
5667
+ const resolvedVersion = await resolveCollectorVersion(flags.version);
5668
+ const schema = await getCollectorComponentSchema(
5669
+ flags.kind,
5670
+ flags.name,
5671
+ resolvedVersion
5672
+ );
5673
+ return { version: resolvedVersion, kind: flags.kind, name: flags.name, schema };
5674
+ });
5675
+ }
5676
+ async function runCollectorReadme(flags) {
5677
+ await runStatic("collector readme", flags, async () => {
5678
+ assertVersion(flags.version);
5679
+ const resolvedVersion = await resolveCollectorVersion(flags.version);
5680
+ const readme = await getCollectorComponentReadme(
5681
+ flags.kind,
5682
+ flags.name,
5683
+ resolvedVersion
5684
+ );
5685
+ return { version: resolvedVersion, kind: flags.kind, name: flags.name, readme };
5686
+ });
5687
+ }
5688
+ async function runCollectorValidateComponent(flags) {
5689
+ await runStatic("collector validate-component", flags, async () => {
5690
+ assertVersion(flags.version);
5691
+ const resolvedVersion = await resolveCollectorVersion(flags.version);
5692
+ const config = readJsonFromStdinOrFile(flags.configFile);
5693
+ const result = await validateCollectorComponentConfig({
5694
+ kind: flags.kind,
5695
+ name: flags.name,
5696
+ version: resolvedVersion,
5697
+ config
5698
+ });
5699
+ return { version: resolvedVersion, kind: flags.kind, name: flags.name, ...result };
5700
+ });
5701
+ }
5702
+ async function runCollectorRefresh(flags) {
5703
+ await runStatic(
5704
+ "collector refresh",
5705
+ flags,
5706
+ async () => refreshCollectorCatalog()
5707
+ );
5708
+ }
5709
+ function registerCollectorCommands(program) {
5710
+ const collectorCmd = new Command10("collector").description(
5711
+ "OpenTelemetry Collector config + schema commands (JSON)"
5712
+ );
5713
+ const validateCmd = addStaticFlags(new Command10("validate")).description("Validate an OTLP receiver config fragment").option("--config-file <path>", "Read JSON config (default: stdin)").action(async function() {
5714
+ const o = this.optsWithGlobals();
5715
+ await runCollectorValidate({
5716
+ ...staticFlagsFromOpts(o),
5717
+ configFile: o.configFile
5718
+ });
5719
+ });
5720
+ const suggestCmd = addStaticFlags(new Command10("suggest")).description("Print a minimal OTLP receiver config").action(async function() {
5721
+ await runCollectorSuggest(staticFlagsFromOpts(this.optsWithGlobals()));
5722
+ });
5723
+ const explainCmd = addStaticFlags(new Command10("explain")).description("Explain OTLP receiver config shape + defaults").action(async function() {
5724
+ await runCollectorExplain(staticFlagsFromOpts(this.optsWithGlobals()));
5725
+ });
5726
+ const versionsCmd = addStaticFlags(new Command10("versions")).description("List supported collector schema versions").action(async function() {
5727
+ await runCollectorVersions(staticFlagsFromOpts(this.optsWithGlobals()));
5728
+ });
5729
+ const componentsCmd = addStaticFlags(new Command10("components")).description("List components for a version (optionally filter by kind)").option("--version <semver>", "Collector version (e.g. 0.110.0)").option(
5730
+ "--kind <kind>",
5731
+ "receiver | processor | exporter | connector | extension"
5732
+ ).action(async function() {
5733
+ const o = this.optsWithGlobals();
5734
+ await runCollectorComponents({
5735
+ ...staticFlagsFromOpts(o),
5736
+ version: o.version,
5737
+ kind: o.kind
5738
+ });
5739
+ });
5740
+ const schemaCmd = addStaticFlags(new Command10("schema")).description("Get JSON Schema for a collector component").requiredOption("--kind <kind>", "Component kind").requiredOption("--name <name>", "Component name").option("--version <semver>", "Collector version").action(async function() {
5741
+ const o = this.optsWithGlobals();
5742
+ await runCollectorSchema({
5743
+ ...staticFlagsFromOpts(o),
5744
+ kind: o.kind,
5745
+ name: o.name,
5746
+ version: o.version
5747
+ });
5748
+ });
5749
+ const readmeCmd = addStaticFlags(new Command10("readme")).description("Get README for a collector component").requiredOption("--kind <kind>", "Component kind").requiredOption("--name <name>", "Component name").option("--version <semver>", "Collector version").action(async function() {
5750
+ const o = this.optsWithGlobals();
5751
+ await runCollectorReadme({
5752
+ ...staticFlagsFromOpts(o),
5753
+ kind: o.kind,
5754
+ name: o.name,
5755
+ version: o.version
5756
+ });
5757
+ });
5758
+ const validateComponentCmd = addStaticFlags(
5759
+ new Command10("validate-component")
5760
+ ).description("Validate component config against upstream schema").requiredOption("--kind <kind>", "Component kind").requiredOption("--name <name>", "Component name").option("--version <semver>", "Collector version").option("--config-file <path>", "Read JSON config (default: stdin)").action(async function() {
5761
+ const o = this.optsWithGlobals();
5762
+ await runCollectorValidateComponent({
5763
+ ...staticFlagsFromOpts(o),
5764
+ kind: o.kind,
5765
+ name: o.name,
5766
+ version: o.version,
5767
+ configFile: o.configFile
5768
+ });
5769
+ });
5770
+ const refreshCmd = addStaticFlags(new Command10("refresh")).description("Refresh in-memory collector metadata cache").action(async function() {
5771
+ await runCollectorRefresh(staticFlagsFromOpts(this.optsWithGlobals()));
5772
+ });
5773
+ collectorCmd.addCommand(validateCmd);
5774
+ collectorCmd.addCommand(suggestCmd);
5775
+ collectorCmd.addCommand(explainCmd);
5776
+ collectorCmd.addCommand(versionsCmd);
5777
+ collectorCmd.addCommand(componentsCmd);
5778
+ collectorCmd.addCommand(schemaCmd);
5779
+ collectorCmd.addCommand(readmeCmd);
5780
+ collectorCmd.addCommand(validateComponentCmd);
5781
+ collectorCmd.addCommand(refreshCmd);
5782
+ program.addCommand(collectorCmd);
5783
+ }
5784
+
4464
5785
  // src/cli.ts
4465
5786
  function createProgram() {
4466
- const program = new Command();
5787
+ const program = new Command11();
4467
5788
  program.name("autotel").description("CLI for autotel - setup wizard, diagnostics, and incremental features").version("0.1.0");
4468
5789
  const addGlobalOptions = (cmd) => {
4469
5790
  return cmd.option("--cwd <path>", "Target directory", process.cwd()).option("--verbose", "Show detailed output").option("--quiet", "Only show warnings and errors");
4470
5791
  };
4471
- const initCmd = new Command("init").description("Initialize autotel in your project").option("--dry-run", "Skip installation and print what would be done").option("--no-install", "Generate files only, skip package installation").option("--print-install-cmd", "Output the install command without running it").option("-y, --yes", "Accept defaults, non-interactive").option("--preset <name>", "Use a quick preset (e.g., node-datadog-pino)").option("--force", "Overwrite existing config (creates backup first)").option("--workspace-root", "Install at workspace root instead of package root").option("--no-detect", "Skip auto-detection of installed deps").option("--detect-only", "Run detection, print the plan, write nothing").option("--plan <path>", "Apply a pre-built InitPlan JSON file").option("--input <path>", "Read InitPlan JSON from stdin (-) or a file").option("--scan-env", "Consent to reading .env / .env.local for backend detection").option("--json", "Emit machine-readable JSON").option("--output-file <path>", "Persist JSON output to this file").option("--no-secrets-in-output", "Redact secret-shaped values").option("--no-interactive", "Never prompt; fail if input would be required").action(async (opts) => {
5792
+ const initCmd = new Command11("init").description("Initialize autotel in your project").option("--dry-run", "Skip installation and print what would be done").option("--no-install", "Generate files only, skip package installation").option("--print-install-cmd", "Output the install command without running it").option("-y, --yes", "Accept defaults, non-interactive").option("--preset <name>", "Use a quick preset (e.g., node-datadog-pino)").option("--force", "Overwrite existing config (creates backup first)").option("--workspace-root", "Install at workspace root instead of package root").option("--no-detect", "Skip auto-detection of installed deps").option("--detect-only", "Run detection, print the plan, write nothing").option("--plan <path>", "Apply a pre-built InitPlan JSON file").option("--input <path>", "Read InitPlan JSON from stdin (-) or a file").option("--scan-env", "Consent to reading .env / .env.local for backend detection").option("--json", "Emit machine-readable JSON").option("--output-file <path>", "Persist JSON output to this file").option("--no-secrets-in-output", "Redact secret-shaped values").option("--no-interactive", "Never prompt; fail if input would be required").action(async (opts) => {
4472
5793
  const options = {
4473
5794
  cwd: opts.cwd ?? process.cwd(),
4474
5795
  dryRun: opts.dryRun ?? false,
@@ -4498,7 +5819,7 @@ function createProgram() {
4498
5819
  });
4499
5820
  addGlobalOptions(initCmd);
4500
5821
  program.addCommand(initCmd);
4501
- const doctorCmd = new Command("doctor").description("Run diagnostics on your autotel setup").option("--json", "Output machine-readable JSON").option("--fix", "Auto-fix resolvable issues").option("--list-checks", "List all available checks").option("--env-file <path>", "Specify env file to check").action(async (opts) => {
5822
+ const doctorCmd = new Command11("doctor").description("Run diagnostics on your autotel setup").option("--json", "Output machine-readable JSON").option("--fix", "Auto-fix resolvable issues").option("--list-checks", "List all available checks").option("--env-file <path>", "Specify env file to check").action(async (opts) => {
4502
5823
  const options = {
4503
5824
  cwd: opts.cwd ?? process.cwd(),
4504
5825
  dryRun: false,
@@ -4516,7 +5837,7 @@ function createProgram() {
4516
5837
  });
4517
5838
  addGlobalOptions(doctorCmd);
4518
5839
  program.addCommand(doctorCmd);
4519
- const addCmd = new Command("add").description("Add a backend, subscriber, plugin, or platform").argument("[type]", "Preset type (backend, subscriber, plugin, platform)").argument("[name]", "Preset name (e.g., datadog, posthog, mongoose)").option("--list", "List available presets for the given type").option("--dry-run", "Skip installation and print what would be done").option("--no-install", "Generate files only, skip package installation").option("--print-install-cmd", "Output the install command without running it").option("-y, --yes", "Accept defaults, non-interactive").option("--force", "Overwrite non-CLI-owned config (creates backup first)").option("--json", "Output machine-readable JSON (for --list)").option("--workspace-root", "Install at workspace root instead of package root").action(async (type, name, opts) => {
5840
+ const addCmd = new Command11("add").description("Add a backend, subscriber, plugin, or platform").argument("[type]", "Preset type (backend, subscriber, plugin, platform)").argument("[name]", "Preset name (e.g., datadog, posthog, mongoose)").option("--list", "List available presets for the given type").option("--dry-run", "Skip installation and print what would be done").option("--no-install", "Generate files only, skip package installation").option("--print-install-cmd", "Output the install command without running it").option("-y, --yes", "Accept defaults, non-interactive").option("--force", "Overwrite non-CLI-owned config (creates backup first)").option("--json", "Output machine-readable JSON (for --list)").option("--workspace-root", "Install at workspace root instead of package root").action(async (type, name, opts) => {
4520
5841
  const options = {
4521
5842
  cwd: opts.cwd ?? process.cwd(),
4522
5843
  dryRun: opts.dryRun ?? false,
@@ -4538,8 +5859,8 @@ function createProgram() {
4538
5859
  });
4539
5860
  addGlobalOptions(addCmd);
4540
5861
  program.addCommand(addCmd);
4541
- const codemodCmd = new Command("codemod").description("Codemod commands for adopting autotel");
4542
- const traceCmd = new Command("trace").description("Wrap functions in trace() with span name from function/variable/method name").argument("<path>", "File path or glob (e.g. src/index.ts, src/**/*.ts)").option("--dry-run", "Print changes without writing files").option("--name-pattern <pattern>", "Span name template: {name}, {file}, {path}").option("--skip <regex>...", "Skip functions whose name matches (repeatable)").option("--print-files", "Print per-file summary (wrapped count, skipped)").action(async (pathArg, opts) => {
5862
+ const codemodCmd = new Command11("codemod").description("Codemod commands for adopting autotel");
5863
+ const traceCmd = new Command11("trace").description("Wrap functions in trace() with span name from function/variable/method name").argument("<path>", "File path or glob (e.g. src/index.ts, src/**/*.ts)").option("--dry-run", "Print changes without writing files").option("--name-pattern <pattern>", "Span name template: {name}, {file}, {path}").option("--skip <regex>...", "Skip functions whose name matches (repeatable)").option("--print-files", "Print per-file summary (wrapped count, skipped)").action(async (pathArg, opts) => {
4543
5864
  const options = {
4544
5865
  cwd: opts.cwd ?? process.cwd(),
4545
5866
  dryRun: opts.dryRun ?? false,
@@ -4559,45 +5880,93 @@ function createProgram() {
4559
5880
  codemodCmd.addCommand(traceCmd);
4560
5881
  addGlobalOptions(codemodCmd);
4561
5882
  program.addCommand(codemodCmd);
4562
- const schemaCmd = new Command("schema").description("Print the CLI manifest as JSON (agent discovery)").option("--output-file <path>", "Persist JSON to a file").option("--no-secrets-in-output", "Redact secret-shaped values").action((opts) => {
5883
+ const schemaCmd = new Command11("schema").description("Print the CLI manifest as JSON (agent discovery)").option("--output-file <path>", "Persist JSON to a file").option("--no-secrets-in-output", "Redact secret-shaped values").action((opts) => {
4563
5884
  runSchema({ outputFile: opts.outputFile, noSecrets: opts.secretsInOutput === false });
4564
5885
  });
4565
- const schemaErrorsCmd = new Command("errors").description("Print error envelope shape + AUTOTEL_E_* codes").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
5886
+ const schemaErrorsCmd = new Command11("errors").description("Print error envelope shape + AUTOTEL_E_* codes").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
4566
5887
  runSchemaErrors({ outputFile: opts.outputFile });
4567
5888
  });
4568
- const schemaOutputsCmd = new Command("outputs").description("Print JSON output shapes per command").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
5889
+ const schemaOutputsCmd = new Command11("outputs").description("Print JSON output shapes per command").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
4569
5890
  runSchemaOutputs({ outputFile: opts.outputFile });
4570
5891
  });
4571
5892
  schemaCmd.addCommand(schemaErrorsCmd);
4572
5893
  schemaCmd.addCommand(schemaOutputsCmd);
4573
5894
  program.addCommand(schemaCmd);
4574
- const commandsCmd = new Command("commands").description("Print compact tool-style listing of commands").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
5895
+ const commandsCmd = new Command11("commands").description("Print compact tool-style listing of commands").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
4575
5896
  runCommandsListing({ outputFile: opts.outputFile });
4576
5897
  });
4577
5898
  program.addCommand(commandsCmd);
4578
- const examplesCmd = new Command("examples").description("Print copy-pasteable examples for a command").argument("[command]", "Command name (omit for all)").option("--output-file <path>", "Persist JSON to a file").action((name, opts) => {
5899
+ const examplesCmd = new Command11("examples").description("Print copy-pasteable examples for a command").argument("[command]", "Command name (omit for all)").option("--output-file <path>", "Persist JSON to a file").action((name, opts) => {
4579
5900
  runExamples(name, { outputFile: opts.outputFile });
4580
5901
  });
4581
5902
  program.addCommand(examplesCmd);
4582
- const versionCmd = new Command("version").description("Print version info as JSON").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
5903
+ const versionCmd = new Command11("version").description("Print version info as JSON").option("--output-file <path>", "Persist JSON to a file").action((opts) => {
4583
5904
  runVersion({ outputFile: opts.outputFile });
4584
5905
  });
4585
5906
  program.addCommand(versionCmd);
5907
+ registerHealthCommands(program);
5908
+ registerDiscoveryCommands(program);
5909
+ registerQueryCommands(program);
5910
+ registerTraceCommands(program);
5911
+ registerTopologyCommands(program);
5912
+ registerDiagnoseCommands(program);
5913
+ registerCorrelateCommands(program);
5914
+ registerLlmCommands(program);
5915
+ registerSemconvCommands(program);
5916
+ registerScoreCommands(program);
5917
+ registerCollectorCommands(program);
4586
5918
  return program;
4587
5919
  }
4588
5920
  async function run() {
4589
5921
  const program = createProgram();
5922
+ program.exitOverride();
5923
+ const argvJoined = process.argv.slice(2).join(" ");
5924
+ const isJsonOnly = process.argv.includes("--json") || /^(schema|commands|examples|version|health|capabilities|discover|query|trace|diagnose|topology|correlate|llm|semconv|score|collector)\b/.test(
5925
+ argvJoined
5926
+ );
5927
+ if (isJsonOnly) {
5928
+ program.configureOutput({ writeErr: () => {
5929
+ } });
5930
+ }
5931
+ const stack = [...program.commands];
5932
+ while (stack.length > 0) {
5933
+ const cmd = stack.pop();
5934
+ cmd.exitOverride();
5935
+ if (isJsonOnly) {
5936
+ cmd.configureOutput({ writeErr: () => {
5937
+ } });
5938
+ }
5939
+ stack.push(...cmd.commands);
5940
+ }
4590
5941
  await program.parseAsync(process.argv);
4591
5942
  }
4592
5943
 
5944
+ // src/lib/commander-error.ts
5945
+ function commanderErrorToAutotel(error2) {
5946
+ if (error2 === null || typeof error2 !== "object" || !("code" in error2) || typeof error2.code !== "string" || !error2.code.startsWith("commander.")) {
5947
+ return null;
5948
+ }
5949
+ const ce = error2;
5950
+ if (ce.code === "commander.help" || ce.code === "commander.helpDisplayed" || ce.code === "commander.version") {
5951
+ process.exit(ce.exitCode ?? 0);
5952
+ }
5953
+ return new AutotelError({
5954
+ type: "validation",
5955
+ code: "AUTOTEL_E_INVALID_FLAG",
5956
+ message: ce.message,
5957
+ retryable: false,
5958
+ expected: { commanderCode: ce.code }
5959
+ });
5960
+ }
5961
+
4593
5962
  // src/index.ts
4594
5963
  function jsonModeRequested() {
4595
5964
  return process.argv.includes("--json");
4596
5965
  }
4597
5966
  run().catch((error2) => {
4598
- const err = toAutotelError(error2);
4599
- const isJson = jsonModeRequested() || // schema/commands/examples/version are JSON-only
4600
- /^(schema|commands|examples|version)\b/.test(
5967
+ const err = commanderErrorToAutotel(error2) ?? toAutotelError(error2);
5968
+ const isJson = jsonModeRequested() || // schema/commands/examples/version + investigate commands are JSON-only
5969
+ /^(schema|commands|examples|version|health|capabilities|discover|query|trace|diagnose|topology|correlate|llm|semconv|score|collector)\b/.test(
4601
5970
  process.argv.slice(2).join(" ")
4602
5971
  );
4603
5972
  if (isJson) {