@agent-nexus/cli 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +789 -70
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -470,6 +470,7 @@ All commands follow the pattern: `nexus <group> <action> [arguments] [options]`
470
470
  | [`eval`](docs/command-reference.md#nexus-eval) | (subgroups: `session`, `dataset`, `execute`, `judge`, `results`, `formats`, `judges`) | AI task evaluation |
471
471
  | [`ticket`](docs/command-reference.md#nexus-ticket) | `list` `get` `create` `update` `comment` `comments` | Bug and feature tracking |
472
472
  | [`phone-number`](docs/command-reference.md#nexus-phone-number) | `search` `buy` `list` `get` `release` | Phone number management |
473
+ | [`channel`](docs/command-reference.md#nexus-channel) | `setup` `connection list\|create` `whatsapp-sender list\|create\|get` | Channel setup orchestrator |
473
474
  | [`prompt-assistant`](docs/command-reference.md#nexus-prompt-assistant) | `chat` `get-thread` `delete-thread` | AI-assisted prompt writing |
474
475
 
475
476
  ### Utility
@@ -600,6 +601,9 @@ Every CLI command maps to an SDK method. Use the SDK (`@agent-nexus/sdk`) when b
600
601
  | `nexus model list` | `client.models.list()` |
601
602
  | `nexus ticket create --title X ...` | `client.tickets.create({ title: "X", ... })` |
602
603
  | `nexus phone-number list` | `client.phoneNumbers.list()` |
604
+ | `nexus channel setup --type WHATSAPP` | `client.channels.getSetupStatus("WHATSAPP")` |
605
+ | `nexus channel connection create` | `client.channels.createConnection()` |
606
+ | `nexus channel whatsapp-sender create` | `client.channels.createWhatsAppSender({ ... })` |
603
607
 
604
608
  > **Full SDK documentation:** See [@agent-nexus/sdk README](../sdk/README.md)
605
609
 
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.10",
169
+ version: "0.1.12",
170
170
  description: "Official CLI for the Nexus AI agent platform.",
171
171
  license: "MIT",
172
172
  keywords: [
@@ -695,6 +695,24 @@ var AgentsResource = class extends BaseResource {
695
695
  return this.http.request("POST", `/agents/${agentId}/generate-profile-picture`, { body });
696
696
  }
697
697
  };
698
+ var AnalyticsResource = class extends BaseResource {
699
+ async getOverview(params) {
700
+ return this.http.request("GET", "/analytics/overview", {
701
+ query: params
702
+ });
703
+ }
704
+ async exportCsv(params) {
705
+ return this.http.requestRaw("GET", "/analytics/export", {
706
+ query: params
707
+ });
708
+ }
709
+ async listFeedback(params) {
710
+ const { data, meta } = await this.http.requestWithMeta("GET", "/analytics/feedback", {
711
+ query: params
712
+ });
713
+ return { data, meta };
714
+ }
715
+ };
698
716
  var ChannelsResource = class extends BaseResource {
699
717
  // ===========================================================================
700
718
  // Setup Orchestrator
@@ -748,23 +766,42 @@ var ChannelsResource = class extends BaseResource {
748
766
  async getWhatsAppSender(senderId) {
749
767
  return this.http.request("GET", `/channels/whatsapp-senders/${senderId}`);
750
768
  }
751
- };
752
- var AnalyticsResource = class extends BaseResource {
753
- async getOverview(params) {
754
- return this.http.request("GET", "/analytics/overview", {
769
+ // ===========================================================================
770
+ // WhatsApp Templates
771
+ // ===========================================================================
772
+ async listWhatsAppTemplates(params) {
773
+ return this.http.request("GET", "/channels/whatsapp-templates", {
755
774
  query: params
756
775
  });
757
776
  }
758
- async exportCsv(params) {
759
- return this.http.requestRaw("GET", "/analytics/export", {
760
- query: params
761
- });
777
+ async createWhatsAppTemplate(body) {
778
+ return this.http.request("POST", "/channels/whatsapp-templates", { body });
762
779
  }
763
- async listFeedback(params) {
764
- const { data, meta } = await this.http.requestWithMeta("GET", "/analytics/feedback", {
765
- query: params
766
- });
767
- return { data, meta };
780
+ async getWhatsAppTemplate(templateId) {
781
+ return this.http.request(
782
+ "GET",
783
+ `/channels/whatsapp-templates/${templateId}`
784
+ );
785
+ }
786
+ async deleteWhatsAppTemplate(templateId) {
787
+ return this.http.request(
788
+ "DELETE",
789
+ `/channels/whatsapp-templates/${templateId}`
790
+ );
791
+ }
792
+ async listTemplateApprovals(params) {
793
+ return this.http.request(
794
+ "GET",
795
+ "/channels/whatsapp-templates/approvals",
796
+ { query: params }
797
+ );
798
+ }
799
+ async submitTemplateApproval(body) {
800
+ return this.http.request(
801
+ "POST",
802
+ "/channels/whatsapp-templates/approvals",
803
+ { body }
804
+ );
768
805
  }
769
806
  };
770
807
  var CloudImportsResource = class extends BaseResource {
@@ -898,6 +935,42 @@ var DeploymentsResource = class extends BaseResource {
898
935
  async updateEmbedConfig(deploymentId, body) {
899
936
  return this.http.request("PATCH", `/deployments/${deploymentId}/embed-config`, { body });
900
937
  }
938
+ // ===========================================================================
939
+ // WhatsApp Deployment Templates
940
+ // ===========================================================================
941
+ async listDeploymentTemplates(deploymentId) {
942
+ return this.http.request(
943
+ "GET",
944
+ `/deployments/${deploymentId}/whatsapp-templates`
945
+ );
946
+ }
947
+ async attachDeploymentTemplate(deploymentId, body) {
948
+ return this.http.request(
949
+ "POST",
950
+ `/deployments/${deploymentId}/whatsapp-templates`,
951
+ { body }
952
+ );
953
+ }
954
+ async updateDeploymentTemplate(deploymentId, templateId, body) {
955
+ return this.http.request(
956
+ "PATCH",
957
+ `/deployments/${deploymentId}/whatsapp-templates/${templateId}`,
958
+ { body }
959
+ );
960
+ }
961
+ async detachDeploymentTemplate(deploymentId, templateId) {
962
+ return this.http.request(
963
+ "DELETE",
964
+ `/deployments/${deploymentId}/whatsapp-templates/${templateId}`
965
+ );
966
+ }
967
+ async updateDeploymentTemplateSettings(deploymentId, body) {
968
+ return this.http.request(
969
+ "PATCH",
970
+ `/deployments/${deploymentId}/whatsapp-templates/settings`,
971
+ { body }
972
+ );
973
+ }
901
974
  };
902
975
  var DocumentTemplateFoldersResource = class extends BaseResource {
903
976
  async list() {
@@ -2471,6 +2544,10 @@ var URL_MAP = {
2471
2544
  production: "https://api.nexusgpt.io",
2472
2545
  dev: "http://localhost:3001"
2473
2546
  };
2547
+ var DASHBOARD_URL_MAP = {
2548
+ production: "https://gpt.nexus",
2549
+ dev: "http://localhost:3000"
2550
+ };
2474
2551
  var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".nexus-mcp");
2475
2552
  var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
2476
2553
  var NEXUSRC_FILENAME = ".nexusrc";
@@ -2657,6 +2734,17 @@ function resolveBaseUrl(override) {
2657
2734
  const env = process.env.NEXUS_ENV ?? "production";
2658
2735
  return URL_MAP[env] ?? URL_MAP.production;
2659
2736
  }
2737
+ function resolveDashboardUrl(override) {
2738
+ if (override) return override;
2739
+ if (process.env.NEXUS_DASHBOARD_URL) return process.env.NEXUS_DASHBOARD_URL;
2740
+ try {
2741
+ const resolved = resolveProfile();
2742
+ if (resolved.profile.dashboardUrl) return resolved.profile.dashboardUrl;
2743
+ } catch {
2744
+ }
2745
+ const env = process.env.NEXUS_ENV ?? "production";
2746
+ return DASHBOARD_URL_MAP[env] ?? DASHBOARD_URL_MAP.production;
2747
+ }
2660
2748
 
2661
2749
  // src/client.ts
2662
2750
  var _lastResolved = null;
@@ -3275,8 +3363,10 @@ Notes:
3275
3363
  Run "nexus auth list" to see all profiles, "nexus auth switch <name>" to change active.`
3276
3364
  ).action(async (opts) => {
3277
3365
  let baseUrl;
3366
+ let dashboardUrl;
3278
3367
  if (opts.env === "dev") {
3279
3368
  baseUrl = "http://localhost:3001";
3369
+ dashboardUrl = "http://localhost:3000";
3280
3370
  }
3281
3371
  const resolvedBaseUrl = baseUrl ?? resolveBaseUrl();
3282
3372
  let apiKey = opts.apiKey;
@@ -3368,6 +3458,7 @@ Notes:
3368
3458
  saveProfile(profileName, {
3369
3459
  apiKey,
3370
3460
  ...baseUrl ? { baseUrl } : {},
3461
+ ...dashboardUrl ? { dashboardUrl } : {},
3371
3462
  ...orgName ? { orgName } : {},
3372
3463
  ...orgId ? { orgId } : {}
3373
3464
  });
@@ -3569,10 +3660,20 @@ function openUrl(url) {
3569
3660
  }
3570
3661
 
3571
3662
  // src/commands/channel.ts
3663
+ var import_node_child_process2 = require("child_process");
3664
+ var import_node_fs2 = require("fs");
3572
3665
  init_output();
3666
+ function openUrl2(url) {
3667
+ const platform = process.platform;
3668
+ const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
3669
+ (0, import_node_child_process2.exec)(`${cmd} ${JSON.stringify(url)}`);
3670
+ }
3573
3671
  function registerChannelCommands(program2) {
3574
3672
  const channel = program2.command("channel").description("Set up deployment channels: connections, phone numbers, WhatsApp senders");
3575
- channel.command("setup").description("Check or auto-provision channel setup prerequisites").requiredOption("--type <type>", "Deployment type (WHATSAPP, TWILIO_SMS, TWILIO_VOICE, EMBED, etc.)").option("--auto", "Auto-provision what is possible (e.g., create messaging connection)").option("--region <region>", "Region for auto-provisioning (us1 or ie1)", "us1").addHelpText(
3673
+ channel.command("setup").description("Check or auto-provision channel setup prerequisites").requiredOption(
3674
+ "--type <type>",
3675
+ "Deployment type (WHATSAPP, TWILIO_SMS, TWILIO_VOICE, EMBED, etc.)"
3676
+ ).option("--auto", "Auto-provision what is possible (e.g., create messaging connection)").option("--region <region>", "Region for auto-provisioning (us1 or ie1)", "us1").addHelpText(
3576
3677
  "after",
3577
3678
  `
3578
3679
  Examples:
@@ -3605,6 +3706,28 @@ Examples:
3605
3706
  process.exitCode = handleError(err);
3606
3707
  }
3607
3708
  });
3709
+ channel.command("connect-waba").description("Open browser to connect your WhatsApp Business Account (Meta signup)").addHelpText(
3710
+ "after",
3711
+ `
3712
+ This step requires a browser \u2014 it cannot be done via API.
3713
+ Opens the Nexus dashboard where you can click "Connect with Meta"
3714
+ to link your WhatsApp Business Account.
3715
+
3716
+ Examples:
3717
+ $ nexus channel connect-waba`
3718
+ ).action(async () => {
3719
+ try {
3720
+ const dashboardUrl = resolveDashboardUrl(program2.optsWithGlobals().dashboardUrl);
3721
+ const url = `${dashboardUrl}/app/connect-waba`;
3722
+ console.log(`Opening ${color.cyan(url)} ...`);
3723
+ console.log("");
3724
+ console.log('Complete the "Connect with Meta" flow in your browser, then verify:');
3725
+ console.log(` ${color.dim("nexus channel setup --type WHATSAPP")}`);
3726
+ openUrl2(url);
3727
+ } catch (err) {
3728
+ process.exitCode = handleError(err);
3729
+ }
3730
+ });
3608
3731
  const connection = channel.command("connection").description("Manage messaging connections");
3609
3732
  connection.command("list").description("List messaging connections").action(async () => {
3610
3733
  try {
@@ -3699,6 +3822,253 @@ Examples:
3699
3822
  process.exitCode = handleError(err);
3700
3823
  }
3701
3824
  });
3825
+ const waTemplate = channel.command("whatsapp-template").description("Manage WhatsApp message templates (Twilio Content API)");
3826
+ waTemplate.command("list").description("List WhatsApp message templates").option("--connection-id <id>", "Filter by messaging connection ID").addHelpText(
3827
+ "after",
3828
+ `
3829
+ Examples:
3830
+ $ nexus channel whatsapp-template list
3831
+ $ nexus channel whatsapp-template list --connection-id abc --json`
3832
+ ).action(async (opts) => {
3833
+ try {
3834
+ const client = createClient(program2.optsWithGlobals());
3835
+ const result = await client.channels.listWhatsAppTemplates({
3836
+ connectionId: opts.connectionId
3837
+ });
3838
+ const data = result?.data ?? result;
3839
+ printTable(Array.isArray(data) ? data : [data], [
3840
+ { key: "id", label: "ID", width: 38 },
3841
+ { key: "friendly_name", label: "FRIENDLY NAME", width: 25 },
3842
+ { key: "language", label: "LANG", width: 8 }
3843
+ ]);
3844
+ } catch (err) {
3845
+ process.exitCode = handleError(err);
3846
+ }
3847
+ });
3848
+ waTemplate.command("get").description("Get WhatsApp template details").argument("<templateId>", "Template ID (Twilio SID)").action(async (templateId) => {
3849
+ try {
3850
+ const client = createClient(program2.optsWithGlobals());
3851
+ const result = await client.channels.getWhatsAppTemplate(templateId);
3852
+ const data = result?.data ?? result;
3853
+ printRecord(data, [
3854
+ { key: "id", label: "ID" },
3855
+ { key: "friendly_name", label: "Friendly Name" },
3856
+ { key: "language", label: "Language" },
3857
+ { key: "types", label: "Types" },
3858
+ { key: "variables", label: "Variables" },
3859
+ { key: "created_at", label: "Created At" }
3860
+ ]);
3861
+ } catch (err) {
3862
+ process.exitCode = handleError(err);
3863
+ }
3864
+ });
3865
+ waTemplate.command("create").description("Create a WhatsApp message template").requiredOption("--connection-id <id>", "Messaging connection ID").requiredOption("--friendly-name <name>", "Template name (e.g., order_confirmation)").requiredOption("--language <lang>", "Language code (e.g., en, en_US)").option("--body <text>", "Template body text (auto-wraps as twilio/text type)").option("--body-file <path>", "Path to JSON file with full Twilio Types object").option("--type <type>", "Twilio type key when using --body", "twilio/text").option("--variables <json>", `Template variables as JSON (e.g., '{"1":"default"}')`).option("--submit", "Also submit for Meta approval after creation").option(
3866
+ "--category <category>",
3867
+ "Approval category (required with --submit): UTILITY, MARKETING, AUTHENTICATION"
3868
+ ).addHelpText(
3869
+ "after",
3870
+ `
3871
+ Examples:
3872
+ $ nexus channel whatsapp-template create --connection-id abc --friendly-name welcome --language en --body "Hello {{1}}, welcome!"
3873
+ $ nexus channel whatsapp-template create --connection-id abc --friendly-name promo --language en --body-file template.json
3874
+ $ nexus channel whatsapp-template create --connection-id abc --friendly-name order --language en --body "Order {{1}} confirmed" --submit --category UTILITY`
3875
+ ).action(async (opts) => {
3876
+ try {
3877
+ if (!opts.body && !opts.bodyFile) {
3878
+ console.error("Error: Either --body or --body-file is required.");
3879
+ process.exitCode = 1;
3880
+ return;
3881
+ }
3882
+ if (opts.body && opts.bodyFile) {
3883
+ console.error("Error: Cannot use both --body and --body-file.");
3884
+ process.exitCode = 1;
3885
+ return;
3886
+ }
3887
+ if (opts.submit && !opts.category) {
3888
+ console.error("Error: --category is required when using --submit.");
3889
+ process.exitCode = 1;
3890
+ return;
3891
+ }
3892
+ let types;
3893
+ if (opts.bodyFile) {
3894
+ try {
3895
+ const content = (0, import_node_fs2.readFileSync)(opts.bodyFile, "utf-8");
3896
+ types = JSON.parse(content);
3897
+ } catch (e) {
3898
+ console.error(
3899
+ `Error reading --body-file: ${e instanceof Error ? e.message : String(e)}`
3900
+ );
3901
+ process.exitCode = 1;
3902
+ return;
3903
+ }
3904
+ } else {
3905
+ types = { [opts.type]: { body: opts.body } };
3906
+ }
3907
+ let variables;
3908
+ if (opts.variables) {
3909
+ try {
3910
+ variables = JSON.parse(opts.variables);
3911
+ } catch {
3912
+ console.error("Error: --variables must be valid JSON.");
3913
+ process.exitCode = 1;
3914
+ return;
3915
+ }
3916
+ }
3917
+ const client = createClient(program2.optsWithGlobals());
3918
+ const result = await client.channels.createWhatsAppTemplate({
3919
+ connectionId: opts.connectionId,
3920
+ friendlyName: opts.friendlyName,
3921
+ language: opts.language,
3922
+ types,
3923
+ variables
3924
+ });
3925
+ const data = result?.data ?? result;
3926
+ printRecord(data, [
3927
+ { key: "id", label: "ID" },
3928
+ { key: "friendly_name", label: "Friendly Name" },
3929
+ { key: "language", label: "Language" },
3930
+ { key: "created_at", label: "Created At" }
3931
+ ]);
3932
+ printSuccess("WhatsApp template created.");
3933
+ if (opts.submit) {
3934
+ console.log("");
3935
+ console.log("Submitting for Meta approval...");
3936
+ const approval = await client.channels.submitTemplateApproval({
3937
+ connectionId: opts.connectionId,
3938
+ templateId: data.id,
3939
+ name: opts.friendlyName,
3940
+ category: opts.category
3941
+ });
3942
+ const approvalData = approval?.data ?? approval;
3943
+ printRecord(approvalData, [
3944
+ { key: "sid", label: "Approval SID" },
3945
+ { key: "status", label: "Status" }
3946
+ ]);
3947
+ printSuccess("Template submitted for Meta approval.");
3948
+ }
3949
+ } catch (err) {
3950
+ process.exitCode = handleError(err);
3951
+ }
3952
+ });
3953
+ waTemplate.command("delete").description("Delete a WhatsApp template").argument("<templateId>", "Template ID (Twilio SID)").option("--yes", "Skip confirmation prompt").action(async (templateId, opts) => {
3954
+ try {
3955
+ if (!opts.yes && process.stdin.isTTY) {
3956
+ const readline2 = await import("readline");
3957
+ const rl = readline2.createInterface({
3958
+ input: process.stdin,
3959
+ output: process.stdout
3960
+ });
3961
+ const answer = await new Promise((resolve) => {
3962
+ rl.question(`Delete template ${templateId}? (y/N) `, resolve);
3963
+ });
3964
+ rl.close();
3965
+ if (answer.toLowerCase() !== "y") {
3966
+ console.log("Cancelled.");
3967
+ return;
3968
+ }
3969
+ }
3970
+ const client = createClient(program2.optsWithGlobals());
3971
+ await client.channels.deleteWhatsAppTemplate(templateId);
3972
+ printSuccess("WhatsApp template deleted.", { id: templateId });
3973
+ } catch (err) {
3974
+ process.exitCode = handleError(err);
3975
+ }
3976
+ });
3977
+ waTemplate.command("approvals").description("List template approval status from Meta").option("--connection-id <id>", "Filter by messaging connection ID").addHelpText(
3978
+ "after",
3979
+ `
3980
+ Examples:
3981
+ $ nexus channel whatsapp-template approvals
3982
+ $ nexus channel whatsapp-template approvals --json`
3983
+ ).action(async (opts) => {
3984
+ try {
3985
+ const client = createClient(program2.optsWithGlobals());
3986
+ const result = await client.channels.listTemplateApprovals({
3987
+ connectionId: opts.connectionId
3988
+ });
3989
+ const data = result?.data ?? result;
3990
+ const items = Array.isArray(data) ? data : [data];
3991
+ const rows = items.map((item) => ({
3992
+ sid: item.sid,
3993
+ name: item.approvalRequests?.name ?? "",
3994
+ category: item.approvalRequests?.category ?? "",
3995
+ status: item.approvalRequests?.status ?? "",
3996
+ rejection_reason: item.approvalRequests?.rejection_reason ?? ""
3997
+ }));
3998
+ printTable(rows, [
3999
+ { key: "sid", label: "SID", width: 38 },
4000
+ { key: "name", label: "NAME", width: 20 },
4001
+ { key: "category", label: "CATEGORY", width: 15 },
4002
+ { key: "status", label: "STATUS", width: 12 },
4003
+ { key: "rejection_reason", label: "REJECTION REASON", width: 30 }
4004
+ ]);
4005
+ } catch (err) {
4006
+ process.exitCode = handleError(err);
4007
+ }
4008
+ });
4009
+ waTemplate.command("submit-approval").description("Submit a template for Meta WhatsApp approval").requiredOption("--connection-id <id>", "Messaging connection ID").requiredOption("--template-id <id>", "Template ID (Twilio SID)").requiredOption("--name <name>", "Template name for approval").requiredOption(
4010
+ "--category <category>",
4011
+ "Approval category: UTILITY, MARKETING, or AUTHENTICATION"
4012
+ ).option("--wait", "Poll approval status until resolved (up to 2 minutes)").addHelpText(
4013
+ "after",
4014
+ `
4015
+ Examples:
4016
+ $ nexus channel whatsapp-template submit-approval --connection-id abc --template-id HX123 --name welcome --category UTILITY
4017
+ $ nexus channel whatsapp-template submit-approval --connection-id abc --template-id HX123 --name promo --category MARKETING --wait`
4018
+ ).action(async (opts) => {
4019
+ try {
4020
+ const client = createClient(program2.optsWithGlobals());
4021
+ const result = await client.channels.submitTemplateApproval({
4022
+ connectionId: opts.connectionId,
4023
+ templateId: opts.templateId,
4024
+ name: opts.name,
4025
+ category: opts.category
4026
+ });
4027
+ const data = result?.data ?? result;
4028
+ printRecord(data, [
4029
+ { key: "sid", label: "Approval SID" },
4030
+ { key: "status", label: "Status" }
4031
+ ]);
4032
+ printSuccess("Template submitted for Meta approval.");
4033
+ if (opts.wait) {
4034
+ const maxWaitMs = 12e4;
4035
+ const intervalMs = 5e3;
4036
+ const startTime = Date.now();
4037
+ let finalStatus = data.status;
4038
+ console.log("Waiting for approval...");
4039
+ while (Date.now() - startTime < maxWaitMs) {
4040
+ await new Promise((r) => setTimeout(r, intervalMs));
4041
+ const approvals = await client.channels.listTemplateApprovals({
4042
+ connectionId: opts.connectionId
4043
+ });
4044
+ const approvalsData = approvals?.data ?? approvals;
4045
+ const items = Array.isArray(approvalsData) ? approvalsData : [approvalsData];
4046
+ const match = items.find((a) => a.sid === opts.templateId);
4047
+ if (match?.approvalRequests?.status) {
4048
+ finalStatus = match.approvalRequests.status;
4049
+ if (finalStatus !== "pending" && finalStatus !== "unsubmitted") {
4050
+ console.log(`Approval resolved: ${color.cyan(finalStatus)}`);
4051
+ if (finalStatus === "rejected" && match.approvalRequests.rejection_reason) {
4052
+ console.log(`Reason: ${match.approvalRequests.rejection_reason}`);
4053
+ }
4054
+ break;
4055
+ }
4056
+ }
4057
+ }
4058
+ if (finalStatus === "pending" || finalStatus === "unsubmitted") {
4059
+ console.log(
4060
+ `Still ${finalStatus} after 2m. Check again: ${color.dim("nexus channel whatsapp-template approvals")}`
4061
+ );
4062
+ }
4063
+ }
4064
+ console.log(
4065
+ `
4066
+ Next: Attach to deployment: ${color.dim("nexus deployment template attach <depId> --template-id ...")}`
4067
+ );
4068
+ } catch (err) {
4069
+ process.exitCode = handleError(err);
4070
+ }
4071
+ });
3702
4072
  }
3703
4073
 
3704
4074
  // src/commands/collection.ts
@@ -4398,6 +4768,171 @@ Examples:
4398
4768
  process.exitCode = handleError(err);
4399
4769
  }
4400
4770
  });
4771
+ const depTemplate = deployment.command("template").description("Manage WhatsApp templates attached to a deployment");
4772
+ depTemplate.command("list").description("List templates attached to a WhatsApp deployment").argument("<deploymentId>", "Deployment ID").addHelpText(
4773
+ "after",
4774
+ `
4775
+ Examples:
4776
+ $ nexus deployment template list dep-123
4777
+ $ nexus deployment template list dep-123 --json`
4778
+ ).action(async (deploymentId) => {
4779
+ try {
4780
+ const client = createClient(program2.optsWithGlobals());
4781
+ const result = await client.deployments.listDeploymentTemplates(deploymentId);
4782
+ const data = result?.data ?? result;
4783
+ const items = Array.isArray(data) ? data : [data];
4784
+ const rows = items.map((t) => ({
4785
+ templateId: t.templateId,
4786
+ name: t.name,
4787
+ type: t.type ?? "template",
4788
+ variables: Object.keys(t.variables ?? {}).length,
4789
+ multiLang: t.enableMultiLanguage ? "yes" : "no"
4790
+ }));
4791
+ printTable(rows, [
4792
+ { key: "templateId", label: "TEMPLATE ID", width: 38 },
4793
+ { key: "name", label: "NAME", width: 20 },
4794
+ { key: "type", label: "TYPE", width: 10 },
4795
+ { key: "variables", label: "VARS", width: 6 },
4796
+ { key: "multiLang", label: "MULTI-LANG", width: 10 }
4797
+ ]);
4798
+ } catch (err) {
4799
+ process.exitCode = handleError(err);
4800
+ }
4801
+ });
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(
4803
+ "after",
4804
+ `
4805
+ Examples:
4806
+ $ 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}}'`
4808
+ ).action(async (deploymentId, opts) => {
4809
+ try {
4810
+ let variables;
4811
+ if (opts.variables) {
4812
+ try {
4813
+ variables = JSON.parse(opts.variables);
4814
+ } catch {
4815
+ console.error("Error: --variables must be valid JSON.");
4816
+ process.exitCode = 1;
4817
+ return;
4818
+ }
4819
+ }
4820
+ const client = createClient(program2.optsWithGlobals());
4821
+ const result = await client.deployments.attachDeploymentTemplate(deploymentId, {
4822
+ templateId: opts.templateId,
4823
+ name: opts.name,
4824
+ description: opts.description,
4825
+ variables,
4826
+ type: opts.type,
4827
+ enableMultiLanguage: opts.enableMultiLanguage
4828
+ });
4829
+ const data = result?.data ?? result;
4830
+ printRecord(data, [
4831
+ { key: "templateId", label: "Template ID" },
4832
+ { key: "name", label: "Name" },
4833
+ { key: "description", label: "Description" },
4834
+ { key: "type", label: "Type" }
4835
+ ]);
4836
+ printSuccess("Template attached to deployment.");
4837
+ } catch (err) {
4838
+ process.exitCode = handleError(err);
4839
+ }
4840
+ });
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(
4842
+ "after",
4843
+ `
4844
+ Examples:
4845
+ $ nexus deployment template update dep-123 HX456 --name "Updated Welcome"
4846
+ $ nexus deployment template update dep-123 HX456 --variables '{"1":{"description":"Full name"}}'`
4847
+ ).action(async (deploymentId, templateId, opts) => {
4848
+ try {
4849
+ const body = {};
4850
+ if (opts.name !== void 0) body.name = opts.name;
4851
+ if (opts.description !== void 0) body.description = opts.description;
4852
+ if (opts.enableMultiLanguage !== void 0)
4853
+ body.enableMultiLanguage = opts.enableMultiLanguage;
4854
+ if (opts.variables) {
4855
+ try {
4856
+ body.variables = JSON.parse(opts.variables);
4857
+ } catch {
4858
+ console.error("Error: --variables must be valid JSON.");
4859
+ process.exitCode = 1;
4860
+ return;
4861
+ }
4862
+ }
4863
+ const client = createClient(program2.optsWithGlobals());
4864
+ const result = await client.deployments.updateDeploymentTemplate(
4865
+ deploymentId,
4866
+ templateId,
4867
+ body
4868
+ );
4869
+ const data = result?.data ?? result;
4870
+ printRecord(data, [
4871
+ { key: "templateId", label: "Template ID" },
4872
+ { key: "name", label: "Name" },
4873
+ { key: "description", label: "Description" }
4874
+ ]);
4875
+ printSuccess("Deployment template updated.");
4876
+ } catch (err) {
4877
+ process.exitCode = handleError(err);
4878
+ }
4879
+ });
4880
+ depTemplate.command("detach").description("Detach a template from a deployment").argument("<deploymentId>", "Deployment ID").argument("<templateId>", "Template ID (Twilio SID)").option("--yes", "Skip confirmation prompt").action(async (deploymentId, templateId, opts) => {
4881
+ try {
4882
+ if (!opts.yes && process.stdin.isTTY) {
4883
+ const readline2 = await import("readline");
4884
+ const rl = readline2.createInterface({
4885
+ input: process.stdin,
4886
+ output: process.stdout
4887
+ });
4888
+ const answer = await new Promise((resolve) => {
4889
+ rl.question(`Detach template ${templateId} from deployment ${deploymentId}? (y/N) `, resolve);
4890
+ });
4891
+ rl.close();
4892
+ if (answer.toLowerCase() !== "y") {
4893
+ console.log("Cancelled.");
4894
+ return;
4895
+ }
4896
+ }
4897
+ const client = createClient(program2.optsWithGlobals());
4898
+ await client.deployments.detachDeploymentTemplate(deploymentId, templateId);
4899
+ printSuccess("Template detached from deployment.", { templateId });
4900
+ } catch (err) {
4901
+ process.exitCode = handleError(err);
4902
+ }
4903
+ });
4904
+ depTemplate.command("settings").description("View or update deployment template settings").argument("<deploymentId>", "Deployment ID").option(
4905
+ "--allow-dynamic-templates <bool>",
4906
+ "Allow agent to dynamically create and send templates (true/false)"
4907
+ ).addHelpText(
4908
+ "after",
4909
+ `
4910
+ Examples:
4911
+ $ nexus deployment template settings dep-123
4912
+ $ nexus deployment template settings dep-123 --allow-dynamic-templates true`
4913
+ ).action(async (deploymentId, opts) => {
4914
+ try {
4915
+ const client = createClient(program2.optsWithGlobals());
4916
+ if (opts.allowDynamicTemplates !== void 0) {
4917
+ const value = opts.allowDynamicTemplates === "true";
4918
+ await client.deployments.updateDeploymentTemplateSettings(deploymentId, {
4919
+ allowAgentToCreateAndSendTemplates: value
4920
+ });
4921
+ printSuccess(
4922
+ `Dynamic template creation ${value ? "enabled" : "disabled"} for deployment.`
4923
+ );
4924
+ } else {
4925
+ const result = await client.deployments.listDeploymentTemplates(deploymentId);
4926
+ const data = result?.data ?? result;
4927
+ console.log(`Templates attached: ${Array.isArray(data) ? data.length : 0}`);
4928
+ console.log(
4929
+ `Tip: Use --allow-dynamic-templates true/false to toggle agent template creation.`
4930
+ );
4931
+ }
4932
+ } catch (err) {
4933
+ process.exitCode = handleError(err);
4934
+ }
4935
+ });
4401
4936
  }
4402
4937
 
4403
4938
  // src/docs-content.generated.ts
@@ -4877,6 +5412,7 @@ All commands follow the pattern: \`nexus <group> <action> [arguments] [options]\
4877
5412
  | [\`eval\`](docs/command-reference.md#nexus-eval) | (subgroups: \`session\`, \`dataset\`, \`execute\`, \`judge\`, \`results\`, \`formats\`, \`judges\`) | AI task evaluation |
4878
5413
  | [\`ticket\`](docs/command-reference.md#nexus-ticket) | \`list\` \`get\` \`create\` \`update\` \`comment\` \`comments\` | Bug and feature tracking |
4879
5414
  | [\`phone-number\`](docs/command-reference.md#nexus-phone-number) | \`search\` \`buy\` \`list\` \`get\` \`release\` | Phone number management |
5415
+ | [\`channel\`](docs/command-reference.md#nexus-channel) | \`setup\` \`connection list\\|create\` \`whatsapp-sender list\\|create\\|get\` | Channel setup orchestrator |
4880
5416
  | [\`prompt-assistant\`](docs/command-reference.md#nexus-prompt-assistant) | \`chat\` \`get-thread\` \`delete-thread\` | AI-assisted prompt writing |
4881
5417
 
4882
5418
  ### Utility
@@ -5007,6 +5543,9 @@ Every CLI command maps to an SDK method. Use the SDK (\`@agent-nexus/sdk\`) when
5007
5543
  | \`nexus model list\` | \`client.models.list()\` |
5008
5544
  | \`nexus ticket create --title X ...\` | \`client.tickets.create({ title: "X", ... })\` |
5009
5545
  | \`nexus phone-number list\` | \`client.phoneNumbers.list()\` |
5546
+ | \`nexus channel setup --type WHATSAPP\` | \`client.channels.getSetupStatus("WHATSAPP")\` |
5547
+ | \`nexus channel connection create\` | \`client.channels.createConnection()\` |
5548
+ | \`nexus channel whatsapp-sender create\` | \`client.channels.createWhatsAppSender({ ... })\` |
5010
5549
 
5011
5550
  > **Full SDK documentation:** See [@agent-nexus/sdk README](../sdk/README.md)
5012
5551
 
@@ -5901,12 +6440,12 @@ List deployments.
5901
6440
  nexus deployment list [options]
5902
6441
  \`\`\`
5903
6442
 
5904
- | Option | Description |
5905
- | ------------------ | --------------------------------------------- |
5906
- | \`--agent-id <id>\` | Filter by agent ID |
5907
- | \`--type <type>\` | Filter by type (\`CHAT\`, \`API\`, \`PHONE\`, etc.) |
5908
- | \`--page <number>\` | Page number |
5909
- | \`--limit <number>\` | Items per page |
6443
+ | Option | Description |
6444
+ | ------------------ | --------------------------------------------------------------- |
6445
+ | \`--agent-id <id>\` | Filter by agent ID |
6446
+ | \`--type <type>\` | Filter by type (\`EMBED\`, \`API\`, \`WHATSAPP\`, \`TWILIO_SMS\`, etc.) |
6447
+ | \`--page <number>\` | Page number |
6448
+ | \`--limit <number>\` | Items per page |
5910
6449
 
5911
6450
  \`\`\`bash
5912
6451
  nexus deployment list
@@ -5943,21 +6482,31 @@ Create a new deployment.
5943
6482
  nexus deployment create [options]
5944
6483
  \`\`\`
5945
6484
 
5946
- | Option | Required | Description |
5947
- | ---------------------- | -------- | ---------------------------------------------------- |
5948
- | \`--agent-id <id>\` | Yes | Agent ID |
5949
- | \`--name <name>\` | Yes | Deployment name |
5950
- | \`--type <type>\` | Yes | Deployment type (\`CHAT\`, \`API\`, \`PHONE\`, etc.) |
5951
- | \`--description <text>\` | No | Deployment description |
5952
- | \`--body <json>\` | No | Request body as JSON, \`.json\` file, or \`-\` for stdin |
6485
+ | Option | Required | Description |
6486
+ | ---------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
6487
+ | \`--name <name>\` | Yes | Deployment name |
6488
+ | \`--type <type>\` | Yes | Deployment type: \`EMBED\`, \`API\`, \`WHATSAPP\`, \`TWILIO_SMS\`, \`TWILIO_VOICE\`, \`TELEGRAM\`, \`SLACK\`, \`GMAIL\`, \`OUTLOOK\`, \`TEAMS\` |
6489
+ | \`--agent-id <id>\` | No | Agent ID |
6490
+ | \`--description <text>\` | No | Deployment description |
6491
+ | \`--body <json>\` | No | Request body as JSON, \`.json\` file, or \`-\` for stdin |
6492
+
6493
+ **Important:** Channel deployments (WhatsApp, SMS, Voice, etc.) have prerequisites. Run \`nexus channel setup --type <TYPE>\` first to see what's needed.
5953
6494
 
5954
6495
  \`\`\`bash
5955
- nexus deployment create --agent-id agt-123 --name "Website Chat" --type CHAT
5956
- nexus deployment create --agent-id agt-123 --name "Support API" --type API
5957
- nexus deployment create --body '{"agentId":"agt-123","name":"Chat","type":"CHAT"}'
6496
+ # Simple deployments (no prerequisites)
6497
+ nexus deployment create --name "Website Chat" --type EMBED --agent-id agt-123
6498
+ nexus deployment create --name "Support API" --type API --agent-id agt-123
6499
+
6500
+ # Channel deployments (require connection + phone + optional sender)
6501
+ # First check prerequisites:
6502
+ nexus channel setup --type WHATSAPP
6503
+
6504
+ # Then create with connection fields via --body:
6505
+ nexus deployment create --name "WhatsApp Support" --type WHATSAPP --agent-id agt-123 \\
6506
+ --body '{"phoneNumberId":"phn-456","apiKeyConnectionId":"conn-789"}'
5958
6507
  \`\`\`
5959
6508
 
5960
- **SDK equivalent:** \`client.deployments.create({ agentId, name, type, ... })\`
6509
+ **SDK equivalent:** \`client.deployments.create({ name, type, agentId, phoneNumberId, apiKeyConnectionId, ... })\`
5961
6510
 
5962
6511
  ### deployment update
5963
6512
 
@@ -8643,9 +9192,142 @@ nexus model list --search "gpt-4"
8643
9192
 
8644
9193
  ---
8645
9194
 
9195
+ ## nexus channel
9196
+
9197
+ Set up deployment channels: connections, phone numbers, and WhatsApp senders. Use \`nexus channel setup\` to see what's needed before creating any non-EMBED/API deployment.
9198
+
9199
+ ### channel setup
9200
+
9201
+ Check or auto-provision channel setup prerequisites. Returns a step-by-step checklist.
9202
+
9203
+ \`\`\`
9204
+ nexus channel setup [options]
9205
+ \`\`\`
9206
+
9207
+ | Option | Required | Description |
9208
+ | ------------------- | -------- | ------------------------------------------------------------------- |
9209
+ | \`--type <type>\` | Yes | Deployment type (\`WHATSAPP\`, \`TWILIO_SMS\`, \`TWILIO_VOICE\`, etc.) |
9210
+ | \`--auto\` | No | Auto-provision what is possible (e.g., create messaging connection) |
9211
+ | \`--region <region>\` | No | Region for auto-provisioning: \`us1\` or \`ie1\` (default: \`us1\`) |
9212
+
9213
+ \`\`\`bash
9214
+ nexus channel setup --type WHATSAPP
9215
+ nexus channel setup --type WHATSAPP --auto
9216
+ nexus channel setup --type TWILIO_SMS --json
9217
+ \`\`\`
9218
+
9219
+ **SDK equivalent:** \`client.channels.getSetupStatus(type)\` / \`client.channels.autoProvision({ type, region })\`
9220
+
9221
+ ### channel connect-waba
9222
+
9223
+ Open the browser to connect your WhatsApp Business Account via Meta's Embedded Signup. This step **requires a browser** and cannot be done via API.
9224
+
9225
+ \`\`\`
9226
+ nexus channel connect-waba
9227
+ \`\`\`
9228
+
9229
+ Opens \`{NEXUS_DASHBOARD_URL}/app/connect-waba\` in your default browser \u2014 a dedicated page with a single "Connect with Meta" button. Complete the flow, then verify with \`nexus channel setup --type WHATSAPP\`.
9230
+
9231
+ \`\`\`bash
9232
+ nexus channel connect-waba
9233
+ \`\`\`
9234
+
9235
+ **SDK equivalent:** N/A (browser-only step)
9236
+
9237
+ ### channel connection list
9238
+
9239
+ List messaging connections for the organization.
9240
+
9241
+ \`\`\`
9242
+ nexus channel connection list
9243
+ \`\`\`
9244
+
9245
+ \`\`\`bash
9246
+ nexus channel connection list --json
9247
+ \`\`\`
9248
+
9249
+ **SDK equivalent:** \`client.channels.listConnections()\`
9250
+
9251
+ ### channel connection create
9252
+
9253
+ Create a messaging connection (max 1 per organization via the API).
9254
+
9255
+ \`\`\`
9256
+ nexus channel connection create [options]
9257
+ \`\`\`
9258
+
9259
+ | Option | Description |
9260
+ | ------------------- | --------------------------------------- |
9261
+ | \`--region <region>\` | Region: \`us1\` or \`ie1\` (default: \`us1\`) |
9262
+
9263
+ \`\`\`bash
9264
+ nexus channel connection create
9265
+ nexus channel connection create --region ie1 --json
9266
+ \`\`\`
9267
+
9268
+ **SDK equivalent:** \`client.channels.createConnection({ region })\`
9269
+
9270
+ ### channel whatsapp-sender list
9271
+
9272
+ List WhatsApp senders for the organization.
9273
+
9274
+ \`\`\`
9275
+ nexus channel whatsapp-sender list
9276
+ \`\`\`
9277
+
9278
+ \`\`\`bash
9279
+ nexus channel whatsapp-sender list --json
9280
+ \`\`\`
9281
+
9282
+ **SDK equivalent:** \`client.channels.listWhatsAppSenders()\`
9283
+
9284
+ ### channel whatsapp-sender create
9285
+
9286
+ Create a WhatsApp sender (registers a phone number with WhatsApp Business via Meta).
9287
+
9288
+ \`\`\`
9289
+ nexus channel whatsapp-sender create [options]
9290
+ \`\`\`
9291
+
9292
+ | Option | Required | Description |
9293
+ | ------------------------ | -------- | --------------------------------------------------------------- |
9294
+ | \`--connection-id <id>\` | Yes | Messaging connection ID |
9295
+ | \`--phone-number-id <id>\` | Yes | Phone number ID |
9296
+ | \`--sender-name <name>\` | Yes | Display name for the WhatsApp sender |
9297
+ | \`--waba-id <id>\` | No | WhatsApp Business Account ID (reads from connection if omitted) |
9298
+
9299
+ \`\`\`bash
9300
+ nexus channel whatsapp-sender create \\
9301
+ --connection-id conn-123 \\
9302
+ --phone-number-id phn-456 \\
9303
+ --sender-name "My Business"
9304
+ \`\`\`
9305
+
9306
+ **SDK equivalent:** \`client.channels.createWhatsAppSender({ connectionId, phoneNumberId, senderName, wabaId })\`
9307
+
9308
+ ### channel whatsapp-sender get
9309
+
9310
+ Get WhatsApp sender details including status.
9311
+
9312
+ \`\`\`
9313
+ nexus channel whatsapp-sender get <id>
9314
+ \`\`\`
9315
+
9316
+ | Argument | Description |
9317
+ | -------- | ----------- |
9318
+ | \`id\` | Sender ID |
9319
+
9320
+ \`\`\`bash
9321
+ nexus channel whatsapp-sender get sender-123 --json
9322
+ \`\`\`
9323
+
9324
+ **SDK equivalent:** \`client.channels.getWhatsAppSender(id)\`
9325
+
9326
+ ---
9327
+
8646
9328
  ## nexus phone-number
8647
9329
 
8648
- Manage phone numbers for voice deployments.
9330
+ Manage phone numbers for SMS, Voice, and WhatsApp deployments.
8649
9331
 
8650
9332
  ### phone-number search
8651
9333
 
@@ -9718,34 +10400,46 @@ Deploy the same agent to multiple channels and monitor analytics.
9718
10400
  # 1. Create an agent (or use an existing one)
9719
10401
  AGENT_ID="your-agent-id"
9720
10402
 
9721
- # 2. Deploy to web widget
10403
+ # 2. Deploy to web widget (no prerequisites)
9722
10404
  WEB_DEP=$(nexus deployment create \\
9723
10405
  --name "Website Widget" \\
9724
- --type web \\
10406
+ --type EMBED \\
9725
10407
  --agent-id $AGENT_ID \\
9726
10408
  --json | jq -r '.id')
9727
10409
 
9728
- # 3. Deploy to WhatsApp
10410
+ # 3. Deploy to WhatsApp (requires channel setup first!)
10411
+ # Check what's needed:
10412
+ nexus channel setup --type WHATSAPP
10413
+
10414
+ # Auto-provision messaging connection:
10415
+ nexus channel setup --type WHATSAPP --auto
10416
+
10417
+ # Buy a phone number:
10418
+ nexus phone-number search --country US --sms
10419
+ nexus phone-number buy --phone-number "+12025551234" --country US --price 1.15
10420
+
10421
+ # Create WhatsApp sender (register with Meta):
10422
+ CONN_ID=$(nexus channel connection list --json | jq -r '.[0].id')
10423
+ PHONE_ID=$(nexus phone-number list --json | jq -r '.[0].id')
10424
+ nexus channel whatsapp-sender create \\
10425
+ --connection-id $CONN_ID \\
10426
+ --phone-number-id $PHONE_ID \\
10427
+ --sender-name "My Business"
10428
+
10429
+ # Now create the WhatsApp deployment:
9729
10430
  WA_DEP=$(nexus deployment create \\
9730
10431
  --name "WhatsApp Support" \\
9731
- --type whatsapp \\
10432
+ --type WHATSAPP \\
9732
10433
  --agent-id $AGENT_ID \\
10434
+ --body "{\\"phoneNumberId\\":\\"$PHONE_ID\\",\\"apiKeyConnectionId\\":\\"$CONN_ID\\"}" \\
9733
10435
  --json | jq -r '.id')
9734
10436
 
9735
- # 4. Deploy to Slack
9736
- SLACK_DEP=$(nexus deployment create \\
9737
- --name "Slack Bot" \\
9738
- --type slack \\
9739
- --agent-id $AGENT_ID \\
9740
- --json | jq -r '.id')
9741
-
9742
- # 5. Organize deployments in a folder
10437
+ # 4. Organize deployments in a folder
9743
10438
  FOLDER_ID=$(nexus deployment folder create --name "Production" --json | jq -r '.id')
9744
10439
  nexus deployment folder assign --deployment-id $WEB_DEP --folder-id $FOLDER_ID
9745
10440
  nexus deployment folder assign --deployment-id $WA_DEP --folder-id $FOLDER_ID
9746
- nexus deployment folder assign --deployment-id $SLACK_DEP --folder-id $FOLDER_ID
9747
10441
 
9748
- # 6. Get the web widget embed configuration
10442
+ # 5. Get the web widget embed configuration
9749
10443
  nexus deployment embed-config $WEB_DEP
9750
10444
 
9751
10445
  # 7. Customize the widget
@@ -10070,7 +10764,7 @@ ${"\u2550".repeat(72)}`);
10070
10764
  }
10071
10765
 
10072
10766
  // src/commands/document.ts
10073
- var import_node_fs2 = __toESM(require("fs"));
10767
+ var import_node_fs3 = __toESM(require("fs"));
10074
10768
  var import_node_path2 = __toESM(require("path"));
10075
10769
  init_output();
10076
10770
  function registerDocumentCommands(program2) {
@@ -10136,12 +10830,12 @@ Examples:
10136
10830
  try {
10137
10831
  const client = createClient(program2.optsWithGlobals());
10138
10832
  const absPath = import_node_path2.default.resolve(filePath);
10139
- if (!import_node_fs2.default.existsSync(absPath)) {
10833
+ if (!import_node_fs3.default.existsSync(absPath)) {
10140
10834
  console.error(`Error: File not found: ${absPath}`);
10141
10835
  process.exitCode = 1;
10142
10836
  return;
10143
10837
  }
10144
- const buffer = import_node_fs2.default.readFileSync(absPath);
10838
+ const buffer = import_node_fs3.default.readFileSync(absPath);
10145
10839
  const blob = new Blob([buffer]);
10146
10840
  const fileName = import_node_path2.default.basename(absPath);
10147
10841
  const doc = await client.documents.uploadFile(blob, fileName, opts.description);
@@ -10780,8 +11474,8 @@ Examples:
10780
11474
  ).action(async (id) => {
10781
11475
  try {
10782
11476
  const client = createClient(program2.optsWithGlobals());
10783
- const exec2 = await client.workflowExecutions.get(id);
10784
- printRecord(exec2, [
11477
+ const exec3 = await client.workflowExecutions.get(id);
11478
+ printRecord(exec3, [
10785
11479
  { key: "id", label: "ID" },
10786
11480
  { key: "workflowId", label: "Workflow" },
10787
11481
  { key: "status", label: "Status" },
@@ -11439,7 +12133,7 @@ Notes:
11439
12133
  }
11440
12134
 
11441
12135
  // src/commands/template.ts
11442
- var import_node_fs3 = __toESM(require("fs"));
12136
+ var import_node_fs4 = __toESM(require("fs"));
11443
12137
  var import_node_path3 = __toESM(require("path"));
11444
12138
  init_output();
11445
12139
  function registerTemplateCommands(program2) {
@@ -11525,12 +12219,12 @@ Examples:
11525
12219
  try {
11526
12220
  const client = createClient(program2.optsWithGlobals());
11527
12221
  const absPath = import_node_path3.default.resolve(opts.file);
11528
- if (!import_node_fs3.default.existsSync(absPath)) {
12222
+ if (!import_node_fs4.default.existsSync(absPath)) {
11529
12223
  console.error(`Error: File not found: ${absPath}`);
11530
12224
  process.exitCode = 1;
11531
12225
  return;
11532
12226
  }
11533
- const buffer = import_node_fs3.default.readFileSync(absPath);
12227
+ const buffer = import_node_fs4.default.readFileSync(absPath);
11534
12228
  const blob = new Blob([buffer]);
11535
12229
  const fileName = import_node_path3.default.basename(absPath);
11536
12230
  const result = await client.skills.uploadDocumentTemplateFile(id, blob, fileName);
@@ -11844,14 +12538,14 @@ Examples:
11844
12538
  }
11845
12539
 
11846
12540
  // src/commands/upgrade.ts
11847
- var import_node_child_process2 = require("child_process");
12541
+ var import_node_child_process3 = require("child_process");
11848
12542
  init_output();
11849
12543
 
11850
12544
  // src/util/package-manager.ts
11851
- var import_node_fs4 = __toESM(require("fs"));
12545
+ var import_node_fs5 = __toESM(require("fs"));
11852
12546
  function detectPackageManager() {
11853
12547
  try {
11854
- const resolved = import_node_fs4.default.realpathSync(process.argv[1]).replace(/\\/g, "/");
12548
+ const resolved = import_node_fs5.default.realpathSync(process.argv[1]).replace(/\\/g, "/");
11855
12549
  if (/[/]\.?pnpm[/]/.test(resolved)) return "pnpm";
11856
12550
  if (/[/]\.yarn[/]/.test(resolved)) return "yarn";
11857
12551
  } catch {
@@ -11882,7 +12576,7 @@ function getGlobalUpdateHint(pkg) {
11882
12576
  }
11883
12577
 
11884
12578
  // src/util/version-check.ts
11885
- var import_node_fs5 = __toESM(require("fs"));
12579
+ var import_node_fs6 = __toESM(require("fs"));
11886
12580
  var import_node_os2 = __toESM(require("os"));
11887
12581
  var import_node_path4 = __toESM(require("path"));
11888
12582
  var PACKAGE_NAME = "@agent-nexus/cli";
@@ -11891,7 +12585,7 @@ var FETCH_TIMEOUT_MS = 3e3;
11891
12585
  var CACHE_FILE = import_node_path4.default.join(import_node_os2.default.homedir(), ".nexus-mcp", "version-check.json");
11892
12586
  function loadCache() {
11893
12587
  try {
11894
- return JSON.parse(import_node_fs5.default.readFileSync(CACHE_FILE, "utf-8"));
12588
+ return JSON.parse(import_node_fs6.default.readFileSync(CACHE_FILE, "utf-8"));
11895
12589
  } catch {
11896
12590
  return null;
11897
12591
  }
@@ -11899,8 +12593,8 @@ function loadCache() {
11899
12593
  function saveCache(cache) {
11900
12594
  try {
11901
12595
  const dir = import_node_path4.default.dirname(CACHE_FILE);
11902
- import_node_fs5.default.mkdirSync(dir, { recursive: true, mode: 448 });
11903
- import_node_fs5.default.writeFileSync(CACHE_FILE, JSON.stringify(cache), { mode: 384 });
12596
+ import_node_fs6.default.mkdirSync(dir, { recursive: true, mode: 448 });
12597
+ import_node_fs6.default.writeFileSync(CACHE_FILE, JSON.stringify(cache), { mode: 384 });
11904
12598
  } catch {
11905
12599
  }
11906
12600
  }
@@ -11987,11 +12681,29 @@ async function autoUpdate(currentVersion) {
11987
12681
 
11988
12682
  // src/commands/upgrade.ts
11989
12683
  var PACKAGE_NAME2 = "@agent-nexus/cli";
12684
+ var UPGRADE_ALIASES = [
12685
+ "update",
12686
+ "latest",
12687
+ "up",
12688
+ "install",
12689
+ "reinstall",
12690
+ "refresh",
12691
+ "fetch",
12692
+ "pull",
12693
+ "sync",
12694
+ "get",
12695
+ "download",
12696
+ "self-update",
12697
+ "selfupdate",
12698
+ "self-upgrade",
12699
+ "selfupgrade",
12700
+ "new",
12701
+ "patch",
12702
+ "bump"
12703
+ ];
11990
12704
  function registerUpgradeCommand(program2) {
11991
12705
  const currentVersion = require_package().version;
11992
- program2.command("upgrade").description("Upgrade the Nexus CLI to the latest version").addHelpText("after", `
11993
- Examples:
11994
- $ nexus upgrade`).action(async () => {
12706
+ const upgradeAction = async () => {
11995
12707
  process.stderr.write(`Current version: ${color.cyan(currentVersion)}
11996
12708
  `);
11997
12709
  process.stderr.write("Checking for updates\u2026\n");
@@ -12009,7 +12721,7 @@ Examples:
12009
12721
  `);
12010
12722
  try {
12011
12723
  const installCmd = getGlobalInstallCommand(PACKAGE_NAME2);
12012
- (0, import_node_child_process2.execSync)(installCmd, { stdio: "inherit" });
12724
+ (0, import_node_child_process3.execSync)(installCmd, { stdio: "inherit" });
12013
12725
  printSuccess(`Successfully upgraded to ${latest}.`, { from: currentVersion, to: latest });
12014
12726
  } catch {
12015
12727
  const fallbackCmd = getGlobalInstallCommand(PACKAGE_NAME2);
@@ -12021,7 +12733,13 @@ Upgrade failed. Try running manually:
12021
12733
  );
12022
12734
  process.exitCode = 1;
12023
12735
  }
12024
- });
12736
+ };
12737
+ program2.command("upgrade").description("Upgrade the Nexus CLI to the latest version").addHelpText("after", `
12738
+ Examples:
12739
+ $ nexus upgrade`).action(upgradeAction);
12740
+ for (const alias of UPGRADE_ALIASES) {
12741
+ program2.command(alias, { hidden: true }).action(upgradeAction);
12742
+ }
12025
12743
  }
12026
12744
 
12027
12745
  // src/commands/version.ts
@@ -12806,7 +13524,7 @@ Examples:
12806
13524
  // src/index.ts
12807
13525
  init_output();
12808
13526
  var { version: VERSION } = require_package();
12809
- var program = new import_commander.Command().name("nexus").description("Official CLI for the Nexus AI agent platform").version(VERSION, "-v, --version").option("--json", "Output as JSON").option("--api-key <key>", "Override API key for this invocation").option("--base-url <url>", "Override API base URL").option("--profile <name>", "Use a specific named profile").option("--no-auto-update", "Disable automatic updates when a new version is detected").hook("preAction", (thisCommand) => {
13527
+ var program = new import_commander.Command().name("nexus").description("Official CLI for the Nexus AI agent platform").version(VERSION, "-v, --version").option("--json", "Output as JSON").option("--api-key <key>", "Override API key for this invocation").option("--base-url <url>", "Override API base URL").option("--dashboard-url <url>", "Override dashboard URL (for browser links)").option("--profile <name>", "Use a specific named profile").option("--no-auto-update", "Disable automatic updates when a new version is detected").hook("preAction", (thisCommand) => {
12810
13528
  const opts = thisCommand.optsWithGlobals();
12811
13529
  if (opts.json) setJsonMode(true);
12812
13530
  const cmdName = thisCommand.name();
@@ -12822,7 +13540,8 @@ var program = new import_commander.Command().name("nexus").description("Official
12822
13540
  "pin",
12823
13541
  "unpin",
12824
13542
  "status",
12825
- "docs"
13543
+ "docs",
13544
+ ...UPGRADE_ALIASES
12826
13545
  ].includes(cmdName);
12827
13546
  if (!skipBanner && !isJsonMode()) {
12828
13547
  try {
@@ -12875,7 +13594,7 @@ if (process.argv.length <= 2) {
12875
13594
  program.parseAsync(process.argv).then(async () => {
12876
13595
  if (isJsonMode()) return;
12877
13596
  const ranCommand = process.argv[2];
12878
- if (ranCommand === "upgrade") return;
13597
+ if (ranCommand === "upgrade" || UPGRADE_ALIASES.includes(ranCommand)) return;
12879
13598
  const opts = program.opts();
12880
13599
  if (opts.autoUpdate) {
12881
13600
  const msg = await autoUpdate(VERSION);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-nexus/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
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.9"
38
+ "@agent-nexus/sdk": "0.1.13"
39
39
  },
40
40
  "scripts": {
41
41
  "gen:docs": "tsx scripts/bundle-docs.ts",