@agent-nexus/cli 0.1.12 → 0.1.13

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.
Files changed (2) hide show
  1. package/dist/index.js +589 -16
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -166,7 +166,7 @@ var require_package = __commonJS({
166
166
  "package.json"(exports2, module2) {
167
167
  module2.exports = {
168
168
  name: "@agent-nexus/cli",
169
- version: "0.1.12",
169
+ version: "0.1.13",
170
170
  description: "Official CLI for the Nexus AI agent platform.",
171
171
  license: "MIT",
172
172
  keywords: [
@@ -778,10 +778,7 @@ var ChannelsResource = class extends BaseResource {
778
778
  return this.http.request("POST", "/channels/whatsapp-templates", { body });
779
779
  }
780
780
  async getWhatsAppTemplate(templateId) {
781
- return this.http.request(
782
- "GET",
783
- `/channels/whatsapp-templates/${templateId}`
784
- );
781
+ return this.http.request("GET", `/channels/whatsapp-templates/${templateId}`);
785
782
  }
786
783
  async deleteWhatsAppTemplate(templateId) {
787
784
  return this.http.request(
@@ -790,11 +787,9 @@ var ChannelsResource = class extends BaseResource {
790
787
  );
791
788
  }
792
789
  async listTemplateApprovals(params) {
793
- return this.http.request(
794
- "GET",
795
- "/channels/whatsapp-templates/approvals",
796
- { query: params }
797
- );
790
+ return this.http.request("GET", "/channels/whatsapp-templates/approvals", {
791
+ query: params
792
+ });
798
793
  }
799
794
  async submitTemplateApproval(body) {
800
795
  return this.http.request(
@@ -2061,6 +2056,64 @@ var ToolDiscoveryResource = class extends BaseResource {
2061
2056
  );
2062
2057
  }
2063
2058
  };
2059
+ var TracingResource = class extends BaseResource {
2060
+ // ── Traces ──────────────────────────────────────────────────────────────
2061
+ async listTraces(params) {
2062
+ const { data, meta } = await this.http.requestWithMeta(
2063
+ "GET",
2064
+ "/tracing/traces",
2065
+ { query: params }
2066
+ );
2067
+ return { data, meta };
2068
+ }
2069
+ async getTrace(traceId) {
2070
+ return this.http.request("GET", `/tracing/traces/${traceId}`);
2071
+ }
2072
+ async deleteTrace(traceId) {
2073
+ return this.http.request("DELETE", `/tracing/traces/${traceId}`);
2074
+ }
2075
+ // ── Generations ─────────────────────────────────────────────────────────
2076
+ async listGenerations(params) {
2077
+ const { data, meta } = await this.http.requestWithMeta(
2078
+ "GET",
2079
+ "/tracing/generations",
2080
+ { query: params }
2081
+ );
2082
+ return { data, meta };
2083
+ }
2084
+ async getGeneration(generationId) {
2085
+ return this.http.request("GET", `/tracing/generations/${generationId}`);
2086
+ }
2087
+ // ── Models ──────────────────────────────────────────────────────────────
2088
+ async listModels() {
2089
+ return this.http.request("GET", "/tracing/models");
2090
+ }
2091
+ // ── Analytics ───────────────────────────────────────────────────────────
2092
+ async getSummary(params) {
2093
+ return this.http.request("GET", "/tracing/analytics/summary", {
2094
+ query: params
2095
+ });
2096
+ }
2097
+ async getCostBreakdown(params) {
2098
+ return this.http.request("GET", "/tracing/analytics/cost-breakdown", {
2099
+ query: params
2100
+ });
2101
+ }
2102
+ async getTimeline(params) {
2103
+ return this.http.request("GET", "/tracing/analytics/timeline", {
2104
+ query: params
2105
+ });
2106
+ }
2107
+ // ── Export ──────────────────────────────────────────────────────────────
2108
+ async exportTrace(traceId, params) {
2109
+ return this.http.request("POST", `/tracing/traces/${traceId}/export`, {
2110
+ body: params
2111
+ });
2112
+ }
2113
+ async bulkExport(params) {
2114
+ return this.http.request("POST", "/tracing/export", { body: params });
2115
+ }
2116
+ };
2064
2117
  var WorkflowExecutionsResource = class extends BaseResource {
2065
2118
  async list(params) {
2066
2119
  const { data, meta } = await this.http.requestWithMeta("GET", "/workflows/executions", {
@@ -2533,6 +2586,7 @@ var NexusClient = class {
2533
2586
  this.phoneNumbers = new PhoneNumbersResource(http);
2534
2587
  this.tickets = new TicketsResource(http);
2535
2588
  this.channels = new ChannelsResource(http);
2589
+ this.tracing = new TracingResource(http);
2536
2590
  }
2537
2591
  };
2538
2592
 
@@ -3663,6 +3717,41 @@ function openUrl(url) {
3663
3717
  var import_node_child_process2 = require("child_process");
3664
3718
  var import_node_fs2 = require("fs");
3665
3719
  init_output();
3720
+ var VARIABLE_PATTERN = /\{\{\d+\}\}/g;
3721
+ function warnIfHighVariableDensity(types) {
3722
+ let warned = false;
3723
+ function checkField(text, fieldLabel) {
3724
+ const matches = text.match(VARIABLE_PATTERN) ?? [];
3725
+ if (matches.length === 0) return;
3726
+ const variableCharsLength = matches.reduce((sum, m) => sum + m.length, 0);
3727
+ const staticLength = text.length - variableCharsLength;
3728
+ if (staticLength < matches.length * 3) {
3729
+ console.warn(
3730
+ color.yellow("\u26A0 Warning:") + ` ${fieldLabel} has very high variable density (${staticLength} static chars, ${matches.length} variable(s)). Meta may reject this with "too many variables for its length."`
3731
+ );
3732
+ warned = true;
3733
+ }
3734
+ }
3735
+ for (const [typeKey, typeValue] of Object.entries(types)) {
3736
+ if (!typeValue || typeof typeValue !== "object") continue;
3737
+ const tv = typeValue;
3738
+ if (typeof tv.body === "string") checkField(tv.body, `${typeKey} body`);
3739
+ if (typeof tv.title === "string") checkField(tv.title, `${typeKey} title`);
3740
+ if (typeof tv.subtitle === "string") checkField(tv.subtitle, `${typeKey} subtitle`);
3741
+ if (Array.isArray(tv.cards)) {
3742
+ tv.cards.forEach((card, i) => {
3743
+ if (typeof card?.body === "string") checkField(card.body, `${typeKey} card[${i}] body`);
3744
+ if (typeof card?.title === "string") checkField(card.title, `${typeKey} card[${i}] title`);
3745
+ });
3746
+ }
3747
+ }
3748
+ if (warned) {
3749
+ console.warn(
3750
+ color.yellow(" Tip:") + " Add more descriptive static text around {{N}} placeholders to avoid Meta rejection.\n"
3751
+ );
3752
+ }
3753
+ return warned;
3754
+ }
3666
3755
  function openUrl2(url) {
3667
3756
  const platform = process.platform;
3668
3757
  const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
@@ -3914,6 +4003,7 @@ Examples:
3914
4003
  return;
3915
4004
  }
3916
4005
  }
4006
+ warnIfHighVariableDensity(types);
3917
4007
  const client = createClient(program2.optsWithGlobals());
3918
4008
  const result = await client.channels.createWhatsAppTemplate({
3919
4009
  connectionId: opts.connectionId,
@@ -3945,6 +4035,44 @@ Examples:
3945
4035
  { key: "status", label: "Status" }
3946
4036
  ]);
3947
4037
  printSuccess("Template submitted for Meta approval.");
4038
+ const pollMaxMs = 3e4;
4039
+ const pollIntervalMs = 5e3;
4040
+ const pollStart = Date.now();
4041
+ let resolved = false;
4042
+ console.log("Checking approval status...");
4043
+ while (Date.now() - pollStart < pollMaxMs) {
4044
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
4045
+ try {
4046
+ const approvals = await client.channels.listTemplateApprovals({
4047
+ connectionId: opts.connectionId
4048
+ });
4049
+ const approvalsArr = approvals?.data ?? approvals;
4050
+ const items = Array.isArray(approvalsArr) ? approvalsArr : [approvalsArr];
4051
+ const match = items.find((a) => a.sid === data.id);
4052
+ if (match?.approvalRequests?.status) {
4053
+ const status = match.approvalRequests.status;
4054
+ if (status === "rejected") {
4055
+ console.log(color.red(`\u2717 Template rejected by Meta: ${status}`));
4056
+ if (match.approvalRequests.rejection_reason) {
4057
+ console.log(` Reason: ${match.approvalRequests.rejection_reason}`);
4058
+ }
4059
+ resolved = true;
4060
+ process.exitCode = 1;
4061
+ break;
4062
+ } else if (status === "approved") {
4063
+ console.log(color.green(`\u2713 Template approved by Meta.`));
4064
+ resolved = true;
4065
+ break;
4066
+ }
4067
+ }
4068
+ } catch {
4069
+ }
4070
+ }
4071
+ if (!resolved) {
4072
+ console.log(
4073
+ `Status still pending. Check later: ${color.dim("nexus channel whatsapp-template approvals")}`
4074
+ );
4075
+ }
3948
4076
  }
3949
4077
  } catch (err) {
3950
4078
  process.exitCode = handleError(err);
@@ -4799,12 +4927,25 @@ Examples:
4799
4927
  process.exitCode = handleError(err);
4800
4928
  }
4801
4929
  });
4802
- depTemplate.command("attach").description("Attach a WhatsApp template to a deployment").argument("<deploymentId>", "Deployment ID").requiredOption("--template-id <id>", "Template ID (Twilio SID)").requiredOption("--name <name>", "Display name for this template").requiredOption("--description <text>", "Description of what this template does").option("--variables <json>", 'Variables JSON: {"1":{"description":"Name","isBodyVariable":true}}').option("--type <type>", "Template type: template, card, or carousel", "template").option("--enable-multi-language", "Enable multi-language support").addHelpText(
4930
+ depTemplate.command("attach").description("Attach a WhatsApp template to a deployment").argument("<deploymentId>", "Deployment ID").requiredOption("--template-id <id>", "Template ID (Twilio SID)").requiredOption("--name <name>", "Display name for this template").requiredOption("--description <text>", "Description of what this template does").option(
4931
+ "--variables <json>",
4932
+ 'Variables JSON: {"1":{"description":"Name","isBodyVariable":true}}'
4933
+ ).option("--type <type>", "Template type: template, card, or carousel", "template").option("--enable-multi-language", "Enable multi-language support").option("--enable-dynamic-size", "Enable dynamic carousel size (carousel only)").option(
4934
+ "--carousel-template-group <json>",
4935
+ "Carousel template group JSON with size variants (carousel only)"
4936
+ ).option(
4937
+ "--single-item-card-template-id <id>",
4938
+ "Fallback card template ID for single-item carousels"
4939
+ ).option(
4940
+ "--single-item-card-template-group <json>",
4941
+ "Single-item card template group JSON for multi-language fallback"
4942
+ ).addHelpText(
4803
4943
  "after",
4804
4944
  `
4805
4945
  Examples:
4806
4946
  $ nexus deployment template attach dep-123 --template-id HX456 --name welcome --description "Welcome message"
4807
- $ nexus deployment template attach dep-123 --template-id HX456 --name order --description "Order confirmation" --variables '{"1":{"description":"Customer name","isBodyVariable":true}}'`
4947
+ $ nexus deployment template attach dep-123 --template-id HX456 --name order --description "Order confirmation" --variables '{"1":{"description":"Customer name","isBodyVariable":true}}'
4948
+ $ nexus deployment template attach dep-123 --template-id HX456 --name products --description "Product carousel" --type carousel --enable-dynamic-size --carousel-template-group '{"baseName":"products","availableTemplates":[{"language":"en","carouselSize":3,"templateId":"HX111"},{"language":"en","carouselSize":5,"templateId":"HX222"}],"minCarouselSize":3,"maxCarouselSize":5}'`
4808
4949
  ).action(async (deploymentId, opts) => {
4809
4950
  try {
4810
4951
  let variables;
@@ -4817,6 +4958,26 @@ Examples:
4817
4958
  return;
4818
4959
  }
4819
4960
  }
4961
+ let carouselTemplateGroup;
4962
+ if (opts.carouselTemplateGroup) {
4963
+ try {
4964
+ carouselTemplateGroup = JSON.parse(opts.carouselTemplateGroup);
4965
+ } catch {
4966
+ console.error("Error: --carousel-template-group must be valid JSON.");
4967
+ process.exitCode = 1;
4968
+ return;
4969
+ }
4970
+ }
4971
+ let singleItemCardTemplateGroup;
4972
+ if (opts.singleItemCardTemplateGroup) {
4973
+ try {
4974
+ singleItemCardTemplateGroup = JSON.parse(opts.singleItemCardTemplateGroup);
4975
+ } catch {
4976
+ console.error("Error: --single-item-card-template-group must be valid JSON.");
4977
+ process.exitCode = 1;
4978
+ return;
4979
+ }
4980
+ }
4820
4981
  const client = createClient(program2.optsWithGlobals());
4821
4982
  const result = await client.deployments.attachDeploymentTemplate(deploymentId, {
4822
4983
  templateId: opts.templateId,
@@ -4824,7 +4985,11 @@ Examples:
4824
4985
  description: opts.description,
4825
4986
  variables,
4826
4987
  type: opts.type,
4827
- enableMultiLanguage: opts.enableMultiLanguage
4988
+ enableMultiLanguage: opts.enableMultiLanguage,
4989
+ enableDynamicSize: opts.enableDynamicSize,
4990
+ carouselTemplateGroup,
4991
+ singleItemCardTemplateId: opts.singleItemCardTemplateId,
4992
+ singleItemCardTemplateGroup
4828
4993
  });
4829
4994
  const data = result?.data ?? result;
4830
4995
  printRecord(data, [
@@ -4838,12 +5003,22 @@ Examples:
4838
5003
  process.exitCode = handleError(err);
4839
5004
  }
4840
5005
  });
4841
- depTemplate.command("update").description("Update a template's configuration on a deployment").argument("<deploymentId>", "Deployment ID").argument("<templateId>", "Template ID (Twilio SID)").option("--name <name>", "New display name").option("--description <text>", "New description").option("--variables <json>", "Updated variables JSON").option("--enable-multi-language", "Enable multi-language support").option("--no-multi-language", "Disable multi-language support").addHelpText(
5006
+ depTemplate.command("update").description("Update a template's configuration on a deployment").argument("<deploymentId>", "Deployment ID").argument("<templateId>", "Template ID (Twilio SID)").option("--name <name>", "New display name").option("--description <text>", "New description").option("--variables <json>", "Updated variables JSON").option("--enable-multi-language", "Enable multi-language support").option("--no-multi-language", "Disable multi-language support").option("--enable-dynamic-size", "Enable dynamic carousel size (carousel only)").option("--no-dynamic-size", "Disable dynamic carousel size").option(
5007
+ "--carousel-template-group <json>",
5008
+ "Carousel template group JSON with size variants (carousel only)"
5009
+ ).option(
5010
+ "--single-item-card-template-id <id>",
5011
+ "Fallback card template ID for single-item carousels"
5012
+ ).option(
5013
+ "--single-item-card-template-group <json>",
5014
+ "Single-item card template group JSON for multi-language fallback"
5015
+ ).addHelpText(
4842
5016
  "after",
4843
5017
  `
4844
5018
  Examples:
4845
5019
  $ nexus deployment template update dep-123 HX456 --name "Updated Welcome"
4846
- $ nexus deployment template update dep-123 HX456 --variables '{"1":{"description":"Full name"}}'`
5020
+ $ nexus deployment template update dep-123 HX456 --variables '{"1":{"description":"Full name"}}'
5021
+ $ nexus deployment template update dep-123 HX456 --enable-dynamic-size --carousel-template-group '{"baseName":"products","availableTemplates":[...]}'`
4847
5022
  ).action(async (deploymentId, templateId, opts) => {
4848
5023
  try {
4849
5024
  const body = {};
@@ -4851,6 +5026,10 @@ Examples:
4851
5026
  if (opts.description !== void 0) body.description = opts.description;
4852
5027
  if (opts.enableMultiLanguage !== void 0)
4853
5028
  body.enableMultiLanguage = opts.enableMultiLanguage;
5029
+ if (opts.enableDynamicSize !== void 0)
5030
+ body.enableDynamicSize = opts.enableDynamicSize;
5031
+ if (opts.singleItemCardTemplateId !== void 0)
5032
+ body.singleItemCardTemplateId = opts.singleItemCardTemplateId;
4854
5033
  if (opts.variables) {
4855
5034
  try {
4856
5035
  body.variables = JSON.parse(opts.variables);
@@ -4860,6 +5039,24 @@ Examples:
4860
5039
  return;
4861
5040
  }
4862
5041
  }
5042
+ if (opts.carouselTemplateGroup) {
5043
+ try {
5044
+ body.carouselTemplateGroup = JSON.parse(opts.carouselTemplateGroup);
5045
+ } catch {
5046
+ console.error("Error: --carousel-template-group must be valid JSON.");
5047
+ process.exitCode = 1;
5048
+ return;
5049
+ }
5050
+ }
5051
+ if (opts.singleItemCardTemplateGroup) {
5052
+ try {
5053
+ body.singleItemCardTemplateGroup = JSON.parse(opts.singleItemCardTemplateGroup);
5054
+ } catch {
5055
+ console.error("Error: --single-item-card-template-group must be valid JSON.");
5056
+ process.exitCode = 1;
5057
+ return;
5058
+ }
5059
+ }
4863
5060
  const client = createClient(program2.optsWithGlobals());
4864
5061
  const result = await client.deployments.updateDeploymentTemplate(
4865
5062
  deploymentId,
@@ -4886,7 +5083,10 @@ Examples:
4886
5083
  output: process.stdout
4887
5084
  });
4888
5085
  const answer = await new Promise((resolve) => {
4889
- rl.question(`Detach template ${templateId} from deployment ${deploymentId}? (y/N) `, resolve);
5086
+ rl.question(
5087
+ `Detach template ${templateId} from deployment ${deploymentId}? (y/N) `,
5088
+ resolve
5089
+ );
4890
5090
  });
4891
5091
  rl.close();
4892
5092
  if (answer.toLowerCase() !== "y") {
@@ -12537,6 +12737,378 @@ Examples:
12537
12737
  });
12538
12738
  }
12539
12739
 
12740
+ // src/commands/tracing.ts
12741
+ init_output();
12742
+ function registerTracingCommands(program2) {
12743
+ const tracing = program2.command("tracing").description("View LLM traces and analytics");
12744
+ addPaginationOptions(
12745
+ tracing.command("traces").description("List LLM traces").option("--status <status>", "Filter by status (IN_PROGRESS, COMPLETED, FAILED)").option("--agent-id <id>", "Filter by agent ID").option("--workflow-id <id>", "Filter by workflow ID").option("--model <name>", "Filter by model name").option("--start-date <iso>", "Filter from date (ISO 8601)").option("--end-date <iso>", "Filter to date (ISO 8601)").option(
12746
+ "--sort-by <field>",
12747
+ "Sort by field (startedAt, totalCostUsd, totalDurationMs)",
12748
+ "startedAt"
12749
+ ).option("--order <dir>", "Sort order (asc, desc)", "desc").addHelpText(
12750
+ "after",
12751
+ `
12752
+ Examples:
12753
+ $ nexus tracing traces
12754
+ $ nexus tracing traces --status FAILED --limit 10
12755
+ $ nexus tracing traces --agent-id abc --start-date 2026-03-01 --json`
12756
+ )
12757
+ ).action(async (opts) => {
12758
+ try {
12759
+ const client = createClient(program2.optsWithGlobals());
12760
+ const { data, meta } = await client.tracing.listTraces({
12761
+ ...getPaginationParams(opts),
12762
+ status: opts.status,
12763
+ agentId: opts.agentId,
12764
+ workflowId: opts.workflowId,
12765
+ model: opts.model,
12766
+ startDate: opts.startDate,
12767
+ endDate: opts.endDate,
12768
+ sortBy: opts.sortBy,
12769
+ order: opts.order
12770
+ });
12771
+ printList(data, meta, [
12772
+ { key: "id", label: "ID", width: 36 },
12773
+ { key: "status", label: "STATUS", width: 12, format: formatStatus },
12774
+ { key: "agentName", label: "AGENT", width: 20 },
12775
+ { key: "workflowName", label: "WORKFLOW", width: 20 },
12776
+ {
12777
+ key: "totalCostUsd",
12778
+ label: "COST ($)",
12779
+ width: 10,
12780
+ format: (v) => v != null ? `$${Number(v).toFixed(4)}` : "-"
12781
+ },
12782
+ {
12783
+ key: "totalDurationMs",
12784
+ label: "DURATION",
12785
+ width: 10,
12786
+ format: (v) => v != null ? `${Number(v)}ms` : "-"
12787
+ },
12788
+ { key: "generationCount", label: "GENS", width: 5 },
12789
+ { key: "startedAt", label: "STARTED", width: 20 }
12790
+ ]);
12791
+ } catch (err) {
12792
+ process.exitCode = handleError(err);
12793
+ }
12794
+ });
12795
+ tracing.command("trace").description("Get trace details with generations").argument("<id>", "Trace ID").addHelpText(
12796
+ "after",
12797
+ `
12798
+ Examples:
12799
+ $ nexus tracing trace abc-123
12800
+ $ nexus tracing trace abc-123 --json`
12801
+ ).action(async (id) => {
12802
+ try {
12803
+ const client = createClient(program2.optsWithGlobals());
12804
+ const trace = await client.tracing.getTrace(id);
12805
+ printRecord(trace, [
12806
+ { key: "id", label: "ID" },
12807
+ { key: "status", label: "Status" },
12808
+ { key: "agentName", label: "Agent" },
12809
+ { key: "workflowName", label: "Workflow" },
12810
+ { key: "totalCostUsd", label: "Cost ($)", format: (v) => v != null ? `$${Number(v).toFixed(4)}` : "-" },
12811
+ { key: "totalInputTokens", label: "Input Tokens" },
12812
+ { key: "totalOutputTokens", label: "Output Tokens" },
12813
+ { key: "totalDurationMs", label: "Duration (ms)" },
12814
+ { key: "startedAt", label: "Started" },
12815
+ { key: "completedAt", label: "Completed" }
12816
+ ]);
12817
+ const gens = trace.generations;
12818
+ if (gens && gens.length > 0) {
12819
+ console.log(`
12820
+ ${color.bold("Generations")} (${gens.length}):
12821
+ `);
12822
+ printList(gens, void 0, [
12823
+ { key: "id", label: "ID", width: 36 },
12824
+ { key: "modelName", label: "MODEL", width: 25 },
12825
+ { key: "status", label: "STATUS", width: 12, format: formatStatus },
12826
+ {
12827
+ key: "costUsd",
12828
+ label: "COST ($)",
12829
+ width: 10,
12830
+ format: (v) => v != null ? `$${Number(v).toFixed(6)}` : "-"
12831
+ },
12832
+ {
12833
+ key: "durationMs",
12834
+ label: "DURATION",
12835
+ width: 10,
12836
+ format: (v) => v != null ? `${v}ms` : "-"
12837
+ }
12838
+ ]);
12839
+ }
12840
+ } catch (err) {
12841
+ process.exitCode = handleError(err);
12842
+ }
12843
+ });
12844
+ tracing.command("delete").description("Delete a trace and its generations").argument("<id>", "Trace ID").addHelpText(
12845
+ "after",
12846
+ `
12847
+ Examples:
12848
+ $ nexus tracing delete abc-123`
12849
+ ).action(async (id) => {
12850
+ try {
12851
+ const client = createClient(program2.optsWithGlobals());
12852
+ await client.tracing.deleteTrace(id);
12853
+ printSuccess("Trace deleted.", { id });
12854
+ } catch (err) {
12855
+ process.exitCode = handleError(err);
12856
+ }
12857
+ });
12858
+ addPaginationOptions(
12859
+ tracing.command("generations").description("List LLM generations across traces").option("--trace-id <id>", "Filter by trace ID").option("--provider <provider>", "Filter by provider (OPEN_AI, ANTHROPIC, GOOGLE_AI)").option("--model <name>", "Filter by model name").option("--status <status>", "Filter by status (PENDING, RUNNING, COMPLETED, FAILED)").option("--agent-id <id>", "Filter by agent ID").option("--task-id <id>", "Filter by task ID").option("--start-date <iso>", "Filter from date").option("--end-date <iso>", "Filter to date").option("--min-cost <usd>", "Minimum cost in USD").option("--max-cost <usd>", "Maximum cost in USD").addHelpText(
12860
+ "after",
12861
+ `
12862
+ Examples:
12863
+ $ nexus tracing generations
12864
+ $ nexus tracing generations --provider ANTHROPIC --status FAILED
12865
+ $ nexus tracing generations --trace-id abc-123 --json`
12866
+ )
12867
+ ).action(async (opts) => {
12868
+ try {
12869
+ const client = createClient(program2.optsWithGlobals());
12870
+ const { data, meta } = await client.tracing.listGenerations({
12871
+ ...getPaginationParams(opts),
12872
+ traceId: opts.traceId,
12873
+ provider: opts.provider,
12874
+ modelName: opts.model,
12875
+ status: opts.status,
12876
+ agentId: opts.agentId,
12877
+ taskId: opts.taskId,
12878
+ startDate: opts.startDate,
12879
+ endDate: opts.endDate,
12880
+ minCostUsd: opts.minCost ? parseFloat(opts.minCost) : void 0,
12881
+ maxCostUsd: opts.maxCost ? parseFloat(opts.maxCost) : void 0
12882
+ });
12883
+ printList(data, meta, [
12884
+ { key: "id", label: "ID", width: 36 },
12885
+ { key: "traceId", label: "TRACE", width: 36 },
12886
+ { key: "modelName", label: "MODEL", width: 25 },
12887
+ { key: "status", label: "STATUS", width: 12, format: formatStatus },
12888
+ {
12889
+ key: "costUsd",
12890
+ label: "COST ($)",
12891
+ width: 10,
12892
+ format: (v) => v != null ? `$${Number(v).toFixed(6)}` : "-"
12893
+ },
12894
+ {
12895
+ key: "durationMs",
12896
+ label: "DURATION",
12897
+ width: 10,
12898
+ format: (v) => v != null ? `${v}ms` : "-"
12899
+ }
12900
+ ]);
12901
+ } catch (err) {
12902
+ process.exitCode = handleError(err);
12903
+ }
12904
+ });
12905
+ tracing.command("generation").description("Get generation details including prompt and response").argument("<id>", "Generation ID").addHelpText(
12906
+ "after",
12907
+ `
12908
+ Examples:
12909
+ $ nexus tracing generation gen-123
12910
+ $ nexus tracing generation gen-123 --json`
12911
+ ).action(async (id) => {
12912
+ try {
12913
+ const client = createClient(program2.optsWithGlobals());
12914
+ const gen = await client.tracing.getGeneration(id);
12915
+ printRecord(gen, [
12916
+ { key: "id", label: "ID" },
12917
+ { key: "traceId", label: "Trace ID" },
12918
+ { key: "provider", label: "Provider" },
12919
+ { key: "modelName", label: "Model" },
12920
+ { key: "status", label: "Status" },
12921
+ { key: "inputTokens", label: "Input Tokens" },
12922
+ { key: "outputTokens", label: "Output Tokens" },
12923
+ {
12924
+ key: "costUsd",
12925
+ label: "Cost ($)",
12926
+ format: (v) => v != null ? `$${Number(v).toFixed(6)}` : "-"
12927
+ },
12928
+ { key: "durationMs", label: "Duration (ms)" },
12929
+ { key: "temperature", label: "Temperature" },
12930
+ { key: "taskName", label: "Task" },
12931
+ { key: "startedAt", label: "Started" },
12932
+ { key: "completedAt", label: "Completed" },
12933
+ { key: "errorMessage", label: "Error" }
12934
+ ]);
12935
+ } catch (err) {
12936
+ process.exitCode = handleError(err);
12937
+ }
12938
+ });
12939
+ tracing.command("models").description("List distinct model names used in traces").addHelpText(
12940
+ "after",
12941
+ `
12942
+ Examples:
12943
+ $ nexus tracing models`
12944
+ ).action(async () => {
12945
+ try {
12946
+ const client = createClient(program2.optsWithGlobals());
12947
+ const models = await client.tracing.listModels();
12948
+ if (Array.isArray(models) && models.length > 0) {
12949
+ for (const m of models) console.log(m);
12950
+ } else {
12951
+ console.log("No models found.");
12952
+ }
12953
+ } catch (err) {
12954
+ process.exitCode = handleError(err);
12955
+ }
12956
+ });
12957
+ tracing.command("summary").description("Get tracing analytics summary").option("--start-date <iso>", "Period start (ISO 8601)").option("--end-date <iso>", "Period end (ISO 8601)").addHelpText(
12958
+ "after",
12959
+ `
12960
+ Examples:
12961
+ $ nexus tracing summary
12962
+ $ nexus tracing summary --start-date 2026-03-01 --end-date 2026-03-30
12963
+ $ nexus tracing summary --json`
12964
+ ).action(async (opts) => {
12965
+ try {
12966
+ const client = createClient(program2.optsWithGlobals());
12967
+ const summary = await client.tracing.getSummary({
12968
+ startDate: opts.startDate,
12969
+ endDate: opts.endDate
12970
+ });
12971
+ printRecord(summary, [
12972
+ { key: "totalTraces", label: "Total Traces" },
12973
+ { key: "completedTraces", label: "Completed" },
12974
+ { key: "failedTraces", label: "Failed" },
12975
+ { key: "inProgressTraces", label: "In Progress" },
12976
+ {
12977
+ key: "totalCostUsd",
12978
+ label: "Total Cost ($)",
12979
+ format: (v) => `$${Number(v).toFixed(4)}`
12980
+ },
12981
+ { key: "totalInputTokens", label: "Input Tokens" },
12982
+ { key: "totalOutputTokens", label: "Output Tokens" },
12983
+ {
12984
+ key: "avgDurationMs",
12985
+ label: "Avg Duration",
12986
+ format: (v) => v != null ? `${Number(v).toFixed(0)}ms` : "-"
12987
+ },
12988
+ { key: "distinctModelCount", label: "Distinct Models" }
12989
+ ]);
12990
+ } catch (err) {
12991
+ process.exitCode = handleError(err);
12992
+ }
12993
+ });
12994
+ tracing.command("cost-breakdown").description("Get cost breakdown by model, agent, or workflow").option("--group-by <key>", "Group by (model, agent, workflow)", "model").option("--start-date <iso>", "Period start").option("--end-date <iso>", "Period end").addHelpText(
12995
+ "after",
12996
+ `
12997
+ Examples:
12998
+ $ nexus tracing cost-breakdown
12999
+ $ nexus tracing cost-breakdown --group-by agent
13000
+ $ nexus tracing cost-breakdown --group-by workflow --json`
13001
+ ).action(async (opts) => {
13002
+ try {
13003
+ const client = createClient(program2.optsWithGlobals());
13004
+ const result = await client.tracing.getCostBreakdown({
13005
+ groupBy: opts.groupBy,
13006
+ startDate: opts.startDate,
13007
+ endDate: opts.endDate
13008
+ });
13009
+ const entries = result.entries ?? [];
13010
+ printList(entries, void 0, [
13011
+ { key: "groupKey", label: "KEY", width: 36 },
13012
+ { key: "groupLabel", label: "LABEL", width: 25 },
13013
+ {
13014
+ key: "totalCostUsd",
13015
+ label: "COST ($)",
13016
+ width: 12,
13017
+ format: (v) => `$${Number(v).toFixed(4)}`
13018
+ },
13019
+ { key: "traceCount", label: "TRACES", width: 8 },
13020
+ { key: "generationCount", label: "GENS", width: 8 },
13021
+ { key: "totalInputTokens", label: "IN TOKENS", width: 12 },
13022
+ { key: "totalOutputTokens", label: "OUT TOKENS", width: 12 }
13023
+ ]);
13024
+ } catch (err) {
13025
+ process.exitCode = handleError(err);
13026
+ }
13027
+ });
13028
+ tracing.command("timeline").description("Get tracing timeline data").option("--granularity <g>", "Granularity (hour, day, week)", "day").option("--start-date <iso>", "Period start").option("--end-date <iso>", "Period end").addHelpText(
13029
+ "after",
13030
+ `
13031
+ Examples:
13032
+ $ nexus tracing timeline
13033
+ $ nexus tracing timeline --granularity hour --start-date 2026-03-29 --json`
13034
+ ).action(async (opts) => {
13035
+ try {
13036
+ const client = createClient(program2.optsWithGlobals());
13037
+ const result = await client.tracing.getTimeline({
13038
+ granularity: opts.granularity,
13039
+ startDate: opts.startDate,
13040
+ endDate: opts.endDate
13041
+ });
13042
+ const points = result.points ?? [];
13043
+ printList(points, void 0, [
13044
+ { key: "date", label: "DATE", width: 22 },
13045
+ { key: "traceCount", label: "TRACES", width: 8 },
13046
+ { key: "generationCount", label: "GENS", width: 8 },
13047
+ {
13048
+ key: "totalCostUsd",
13049
+ label: "COST ($)",
13050
+ width: 12,
13051
+ format: (v) => `$${Number(v).toFixed(4)}`
13052
+ },
13053
+ {
13054
+ key: "avgDurationMs",
13055
+ label: "AVG DUR",
13056
+ width: 10,
13057
+ format: (v) => v != null ? `${Number(v).toFixed(0)}ms` : "-"
13058
+ }
13059
+ ]);
13060
+ } catch (err) {
13061
+ process.exitCode = handleError(err);
13062
+ }
13063
+ });
13064
+ tracing.command("export").description("Export a single trace").argument("<id>", "Trace ID").option("--format <fmt>", "Output format (json, csv)", "json").addHelpText(
13065
+ "after",
13066
+ `
13067
+ Examples:
13068
+ $ nexus tracing export abc-123
13069
+ $ nexus tracing export abc-123 --format csv > trace.csv`
13070
+ ).action(async (id, opts) => {
13071
+ try {
13072
+ const client = createClient(program2.optsWithGlobals());
13073
+ const result = await client.tracing.exportTrace(id, { format: opts.format });
13074
+ console.log(result.content);
13075
+ } catch (err) {
13076
+ process.exitCode = handleError(err);
13077
+ }
13078
+ });
13079
+ tracing.command("export-bulk").description("Bulk export traces (max 1000)").option("--format <fmt>", "Output format (json, csv)", "json").option("--status <status>", "Filter by status").option("--agent-id <id>", "Filter by agent ID").option("--workflow-id <id>", "Filter by workflow ID").option("--start-date <iso>", "Filter from date").option("--end-date <iso>", "Filter to date").option("--limit <n>", "Max traces to export", "100").addHelpText(
13080
+ "after",
13081
+ `
13082
+ Examples:
13083
+ $ nexus tracing export-bulk --format csv > traces.csv
13084
+ $ nexus tracing export-bulk --status FAILED --limit 50`
13085
+ ).action(async (opts) => {
13086
+ try {
13087
+ const client = createClient(program2.optsWithGlobals());
13088
+ const result = await client.tracing.bulkExport({
13089
+ format: opts.format,
13090
+ status: opts.status,
13091
+ agentId: opts.agentId,
13092
+ workflowId: opts.workflowId,
13093
+ startDate: opts.startDate,
13094
+ endDate: opts.endDate,
13095
+ limit: parseInt(opts.limit, 10)
13096
+ });
13097
+ console.log(result.content);
13098
+ } catch (err) {
13099
+ process.exitCode = handleError(err);
13100
+ }
13101
+ });
13102
+ }
13103
+ function formatStatus(v) {
13104
+ const s = String(v);
13105
+ if (s === "COMPLETED") return color.green(s);
13106
+ if (s === "FAILED") return color.red(s);
13107
+ if (s === "IN_PROGRESS" || s === "RUNNING") return color.yellow(s);
13108
+ if (s === "PENDING") return color.dim(s);
13109
+ return s;
13110
+ }
13111
+
12540
13112
  // src/commands/upgrade.ts
12541
13113
  var import_node_child_process3 = require("child_process");
12542
13114
  init_output();
@@ -13586,6 +14158,7 @@ registerModelCommands(program);
13586
14158
  registerCustomModelCommands(program);
13587
14159
  registerPhoneNumberCommands(program);
13588
14160
  registerChannelCommands(program);
14161
+ registerTracingCommands(program);
13589
14162
  registerUpgradeCommand(program);
13590
14163
  registerDocsCommand(program);
13591
14164
  if (process.argv.length <= 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-nexus/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Official CLI for the Nexus AI agent platform.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  "@types/node": "24.6.2",
36
36
  "tsup": "^8.5.0",
37
37
  "typescript": "^5.8.3",
38
- "@agent-nexus/sdk": "0.1.13"
38
+ "@agent-nexus/sdk": "0.1.15"
39
39
  },
40
40
  "scripts": {
41
41
  "gen:docs": "tsx scripts/bundle-docs.ts",