@stephendolan/helpscout-cli 1.0.0 → 1.0.2

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/cli.js CHANGED
@@ -340,10 +340,7 @@ var HelpScoutClient = class {
340
340
  const appSecret = await auth.getAppSecret();
341
341
  const refreshToken = await auth.getRefreshToken();
342
342
  if (!appId || !appSecret) {
343
- throw new HelpScoutCliError(
344
- "Not configured. Please run: helpscout auth login",
345
- 401
346
- );
343
+ throw new HelpScoutCliError("Not configured. Please run: helpscout auth login", 401);
347
344
  }
348
345
  if (refreshToken) {
349
346
  try {
@@ -368,7 +365,12 @@ var HelpScoutClient = class {
368
365
  }
369
366
  } catch (error) {
370
367
  const message = error instanceof Error ? error.message : "Unknown error";
371
- console.error(JSON.stringify({ warning: "Refresh token failed, using client credentials", reason: message }));
368
+ console.error(
369
+ JSON.stringify({
370
+ warning: "Refresh token failed, using client credentials",
371
+ reason: message
372
+ })
373
+ );
372
374
  }
373
375
  }
374
376
  let response;
@@ -442,7 +444,9 @@ var HelpScoutClient = class {
442
444
  if (response.status === 429 && rateLimitRetry) {
443
445
  const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
444
446
  const waitSeconds = Math.min(retryAfter, 120);
445
- console.error(JSON.stringify({ warning: `Rate limited. Waiting ${waitSeconds}s before retry...` }));
447
+ console.error(
448
+ JSON.stringify({ warning: `Rate limited. Waiting ${waitSeconds}s before retry...` })
449
+ );
446
450
  await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1e3));
447
451
  return this.request(method, path, { ...options, rateLimitRetry: false });
448
452
  }
@@ -541,11 +545,9 @@ var HelpScoutClient = class {
541
545
  }
542
546
  // Tags
543
547
  async listTags(page) {
544
- const response = await this.request(
545
- "GET",
546
- "/tags",
547
- { params: page ? { page } : void 0 }
548
- );
548
+ const response = await this.request("GET", "/tags", {
549
+ params: page ? { page } : void 0
550
+ });
549
551
  return {
550
552
  tags: response._embedded?.tags || [],
551
553
  page: response.page
@@ -641,32 +643,40 @@ async function confirmDelete(resourceType, skipConfirmation) {
641
643
  // src/commands/auth.ts
642
644
  function createAuthCommand() {
643
645
  const cmd = new Command("auth").description("Authentication operations");
644
- cmd.command("login").description("Configure Help Scout API credentials").requiredOption("--app-id <id>", "Help Scout App ID").requiredOption("--app-secret <secret>", "Help Scout App Secret").action(withErrorHandling(async (options) => {
645
- await auth.setAppId(options.appId);
646
- await auth.setAppSecret(options.appSecret);
647
- client.clearToken();
648
- await client.refreshAccessToken();
649
- outputJson({ message: "Successfully authenticated with Help Scout" });
650
- }));
651
- cmd.command("logout").description("Remove stored credentials").action(withErrorHandling(async () => {
652
- await auth.logout();
653
- client.clearToken();
654
- outputJson({ message: "Logged out successfully" });
655
- }));
656
- cmd.command("status").description("Check authentication status").action(withErrorHandling(async () => {
657
- const hasToken = await auth.isAuthenticated();
658
- const hasAppId = !!await auth.getAppId();
659
- const hasAppSecret = !!await auth.getAppSecret();
660
- outputJson({
661
- authenticated: hasToken,
662
- configured: hasAppId && hasAppSecret
663
- });
664
- }));
665
- cmd.command("refresh").description("Refresh access token").action(withErrorHandling(async () => {
666
- client.clearToken();
667
- await client.refreshAccessToken();
668
- outputJson({ message: "Access token refreshed" });
669
- }));
646
+ cmd.command("login").description("Configure Help Scout API credentials").requiredOption("--app-id <id>", "Help Scout App ID").requiredOption("--app-secret <secret>", "Help Scout App Secret").action(
647
+ withErrorHandling(async (options) => {
648
+ await auth.setAppId(options.appId);
649
+ await auth.setAppSecret(options.appSecret);
650
+ client.clearToken();
651
+ await client.refreshAccessToken();
652
+ outputJson({ message: "Successfully authenticated with Help Scout" });
653
+ })
654
+ );
655
+ cmd.command("logout").description("Remove stored credentials").action(
656
+ withErrorHandling(async () => {
657
+ await auth.logout();
658
+ client.clearToken();
659
+ outputJson({ message: "Logged out successfully" });
660
+ })
661
+ );
662
+ cmd.command("status").description("Check authentication status").action(
663
+ withErrorHandling(async () => {
664
+ const hasToken = await auth.isAuthenticated();
665
+ const hasAppId = !!await auth.getAppId();
666
+ const hasAppSecret = !!await auth.getAppSecret();
667
+ outputJson({
668
+ authenticated: hasToken,
669
+ configured: hasAppId && hasAppSecret
670
+ });
671
+ })
672
+ );
673
+ cmd.command("refresh").description("Refresh access token").action(
674
+ withErrorHandling(async () => {
675
+ client.clearToken();
676
+ await client.refreshAccessToken();
677
+ outputJson({ message: "Access token refreshed" });
678
+ })
679
+ );
670
680
  return cmd;
671
681
  }
672
682
 
@@ -674,27 +684,39 @@ function createAuthCommand() {
674
684
  import { Command as Command2 } from "commander";
675
685
  function createMailboxesCommand() {
676
686
  const cmd = new Command2("mailboxes").description("Mailbox operations");
677
- cmd.command("list").description("List mailboxes").option("--page <number>", "Page number").action(withErrorHandling(async (options) => {
678
- const result = await client.listMailboxes(options.page ? parseInt(options.page, 10) : void 0);
679
- outputJson(result);
680
- }));
681
- cmd.command("view").description("View a mailbox").argument("<id>", "Mailbox ID").action(withErrorHandling(async (id) => {
682
- const mailbox = await client.getMailbox(parseIdArg(id, "mailbox"));
683
- outputJson(mailbox);
684
- }));
685
- cmd.command("set-default").description("Set default mailbox").argument("<id>", "Mailbox ID").action(withErrorHandling(async (id) => {
686
- const mailboxId = parseIdArg(id, "mailbox");
687
- config.setDefaultMailbox(String(mailboxId));
688
- outputJson({ message: `Default mailbox set to ${mailboxId}` });
689
- }));
690
- cmd.command("get-default").description("Get default mailbox").action(withErrorHandling(async () => {
691
- const mailboxId = config.getDefaultMailbox();
692
- outputJson({ defaultMailbox: mailboxId || null });
693
- }));
694
- cmd.command("clear-default").description("Clear default mailbox").action(withErrorHandling(async () => {
695
- config.clearDefaultMailbox();
696
- outputJson({ message: "Default mailbox cleared" });
697
- }));
687
+ cmd.command("list").description("List mailboxes").option("--page <number>", "Page number").action(
688
+ withErrorHandling(async (options) => {
689
+ const result = await client.listMailboxes(
690
+ options.page ? parseInt(options.page, 10) : void 0
691
+ );
692
+ outputJson(result);
693
+ })
694
+ );
695
+ cmd.command("view").description("View a mailbox").argument("<id>", "Mailbox ID").action(
696
+ withErrorHandling(async (id) => {
697
+ const mailbox = await client.getMailbox(parseIdArg(id, "mailbox"));
698
+ outputJson(mailbox);
699
+ })
700
+ );
701
+ cmd.command("set-default").description("Set default mailbox").argument("<id>", "Mailbox ID").action(
702
+ withErrorHandling(async (id) => {
703
+ const mailboxId = parseIdArg(id, "mailbox");
704
+ config.setDefaultMailbox(String(mailboxId));
705
+ outputJson({ message: `Default mailbox set to ${mailboxId}` });
706
+ })
707
+ );
708
+ cmd.command("get-default").description("Get default mailbox").action(
709
+ withErrorHandling(async () => {
710
+ const mailboxId = config.getDefaultMailbox();
711
+ outputJson({ defaultMailbox: mailboxId || null });
712
+ })
713
+ );
714
+ cmd.command("clear-default").description("Clear default mailbox").action(
715
+ withErrorHandling(async () => {
716
+ config.clearDefaultMailbox();
717
+ outputJson({ message: "Default mailbox cleared" });
718
+ })
719
+ );
698
720
  return cmd;
699
721
  }
700
722
 
@@ -724,78 +746,114 @@ function summarizeConversations(conversations) {
724
746
  }
725
747
  function createConversationsCommand() {
726
748
  const cmd = new Command3("conversations").description("Conversation operations");
727
- cmd.command("list").description("List conversations").option("-m, --mailbox <id>", "Filter by mailbox ID").option("-s, --status <status>", "Filter by status (active, all, closed, open, pending, spam)").option("-t, --tag <tags>", "Filter by tag(s), comma-separated").option("--assigned-to <id>", "Filter by assignee user ID").option("--modified-since <date>", "Filter by modified date (ISO 8601)").option("--sort-field <field>", "Sort by field (createdAt, modifiedAt, number, status, subject)").option("--sort-order <order>", "Sort order (asc, desc)").option("--page <number>", "Page number").option("--embed <resources>", "Embed resources (threads)").option("-q, --query <query>", "Advanced search query (see https://docs.helpscout.com/article/47-search-filters-with-operators)").option("--summary", "Output aggregated summary instead of full conversation list").action(withErrorHandling(async (options) => {
728
- if (options.summary) {
729
- const allConversations = await client.listAllConversations({
730
- mailbox: options.mailbox,
731
- status: options.status,
732
- tag: options.tag,
733
- assignedTo: options.assignedTo,
734
- modifiedSince: options.modifiedSince,
735
- query: options.query
736
- });
737
- const summary = summarizeConversations(allConversations);
738
- outputJson(summary);
739
- return;
740
- }
741
- const result = await client.listConversations({
742
- mailbox: options.mailbox,
743
- status: options.status,
744
- tag: options.tag,
745
- assignedTo: options.assignedTo,
746
- modifiedSince: options.modifiedSince,
747
- sortField: options.sortField,
748
- sortOrder: options.sortOrder,
749
- page: options.page ? parseInt(options.page, 10) : void 0,
750
- embed: options.embed,
751
- query: options.query
752
- });
753
- outputJson(result);
754
- }));
755
- cmd.command("view").description("View a conversation").argument("<id>", "Conversation ID").option("--embed <resources>", "Embed resources (threads)").action(withErrorHandling(async (id, options) => {
756
- const conversation = await client.getConversation(parseIdArg(id, "conversation"), options.embed);
757
- outputJson(conversation);
758
- }));
759
- cmd.command("threads").description("List threads for a conversation (defaults to email communications only)").argument("<id>", "Conversation ID").option("--include-notes", "Include internal notes").option("--all", "Show all thread types including lineitems, workflows, etc.").option("-t, --type <types>", "Filter by specific thread type(s), comma-separated (customer, message, note, lineitem, chat, phone, forwardchild, forwardparent, beaconchat)").action(withErrorHandling(async (id, options) => {
760
- let threads = await client.getConversationThreads(parseIdArg(id, "conversation"));
761
- if (options.type) {
762
- const types = options.type.split(",").map((t) => t.trim().toLowerCase());
763
- threads = threads.filter((t) => types.includes(t.type));
764
- } else if (!options.all) {
765
- const allowedTypes = options.includeNotes ? ["customer", "message", "note", "chat", "phone"] : ["customer", "message", "chat", "phone"];
766
- threads = threads.filter((t) => allowedTypes.includes(t.type));
767
- }
768
- outputJson(threads);
769
- }));
770
- cmd.command("delete").description("Delete a conversation").argument("<id>", "Conversation ID").option("-y, --yes", "Skip confirmation").action(withErrorHandling(async (id, options) => {
771
- await confirmDelete("conversation", options.yes);
772
- await client.deleteConversation(parseIdArg(id, "conversation"));
773
- outputJson({ message: "Conversation deleted" });
774
- }));
775
- cmd.command("add-tag").description("Add a tag to a conversation").argument("<id>", "Conversation ID").argument("<tag>", "Tag name").action(withErrorHandling(async (id, tag) => {
776
- await client.addConversationTag(parseIdArg(id, "conversation"), tag);
777
- outputJson({ message: `Tag "${tag}" added` });
778
- }));
779
- cmd.command("remove-tag").description("Remove a tag from a conversation").argument("<id>", "Conversation ID").argument("<tag>", "Tag name").action(withErrorHandling(async (id, tag) => {
780
- await client.removeConversationTag(parseIdArg(id, "conversation"), tag);
781
- outputJson({ message: `Tag "${tag}" removed` });
782
- }));
783
- cmd.command("reply").description("Reply to a conversation").argument("<id>", "Conversation ID").requiredOption("--text <text>", "Reply text").option("--user <id>", "User ID sending the reply").option("--draft", "Save as draft").option("--status <status>", "Set conversation status after reply (active, closed, pending)").action(withErrorHandling(async (id, options) => {
784
- await client.createReply(parseIdArg(id, "conversation"), {
785
- text: options.text,
786
- user: options.user ? parseIdArg(options.user, "user") : void 0,
787
- draft: options.draft,
788
- status: options.status
789
- });
790
- outputJson({ message: "Reply sent" });
791
- }));
792
- cmd.command("note").description("Add a note to a conversation").argument("<id>", "Conversation ID").requiredOption("--text <text>", "Note text").option("--user <id>", "User ID adding the note").action(withErrorHandling(async (id, options) => {
793
- await client.createNote(parseIdArg(id, "conversation"), {
794
- text: options.text,
795
- user: options.user ? parseIdArg(options.user, "user") : void 0
796
- });
797
- outputJson({ message: "Note added" });
798
- }));
749
+ cmd.command("list").description("List conversations").option("-m, --mailbox <id>", "Filter by mailbox ID").option("-s, --status <status>", "Filter by status (active, all, closed, open, pending, spam)").option("-t, --tag <tags>", "Filter by tag(s), comma-separated").option("--assigned-to <id>", "Filter by assignee user ID").option("--modified-since <date>", "Filter by modified date (ISO 8601)").option(
750
+ "--sort-field <field>",
751
+ "Sort by field (createdAt, modifiedAt, number, status, subject)"
752
+ ).option("--sort-order <order>", "Sort order (asc, desc)").option("--page <number>", "Page number").option("--embed <resources>", "Embed resources (threads)").option(
753
+ "-q, --query <query>",
754
+ "Advanced search query (see https://docs.helpscout.com/article/47-search-filters-with-operators)"
755
+ ).option("--summary", "Output aggregated summary instead of full conversation list").action(
756
+ withErrorHandling(
757
+ async (options) => {
758
+ if (options.summary) {
759
+ const allConversations = await client.listAllConversations({
760
+ mailbox: options.mailbox,
761
+ status: options.status,
762
+ tag: options.tag,
763
+ assignedTo: options.assignedTo,
764
+ modifiedSince: options.modifiedSince,
765
+ query: options.query
766
+ });
767
+ const summary = summarizeConversations(allConversations);
768
+ outputJson(summary);
769
+ return;
770
+ }
771
+ const result = await client.listConversations({
772
+ mailbox: options.mailbox,
773
+ status: options.status,
774
+ tag: options.tag,
775
+ assignedTo: options.assignedTo,
776
+ modifiedSince: options.modifiedSince,
777
+ sortField: options.sortField,
778
+ sortOrder: options.sortOrder,
779
+ page: options.page ? parseInt(options.page, 10) : void 0,
780
+ embed: options.embed,
781
+ query: options.query
782
+ });
783
+ outputJson(result);
784
+ }
785
+ )
786
+ );
787
+ cmd.command("view").description("View a conversation").argument("<id>", "Conversation ID").option("--embed <resources>", "Embed resources (threads)").action(
788
+ withErrorHandling(async (id, options) => {
789
+ const conversation = await client.getConversation(
790
+ parseIdArg(id, "conversation"),
791
+ options.embed
792
+ );
793
+ outputJson(conversation);
794
+ })
795
+ );
796
+ cmd.command("threads").description("List threads for a conversation (defaults to email communications only)").argument("<id>", "Conversation ID").option("--include-notes", "Include internal notes").option("--all", "Show all thread types including lineitems, workflows, etc.").option(
797
+ "-t, --type <types>",
798
+ "Filter by specific thread type(s), comma-separated (customer, message, note, lineitem, chat, phone, forwardchild, forwardparent, beaconchat)"
799
+ ).action(
800
+ withErrorHandling(
801
+ async (id, options) => {
802
+ let threads = await client.getConversationThreads(parseIdArg(id, "conversation"));
803
+ if (options.type) {
804
+ const types = options.type.split(",").map((t) => t.trim().toLowerCase());
805
+ threads = threads.filter((t) => types.includes(t.type));
806
+ } else if (!options.all) {
807
+ const allowedTypes = options.includeNotes ? ["customer", "message", "note", "chat", "phone"] : ["customer", "message", "chat", "phone"];
808
+ threads = threads.filter((t) => allowedTypes.includes(t.type));
809
+ }
810
+ outputJson(threads);
811
+ }
812
+ )
813
+ );
814
+ cmd.command("delete").description("Delete a conversation").argument("<id>", "Conversation ID").option("-y, --yes", "Skip confirmation").action(
815
+ withErrorHandling(async (id, options) => {
816
+ await confirmDelete("conversation", options.yes);
817
+ await client.deleteConversation(parseIdArg(id, "conversation"));
818
+ outputJson({ message: "Conversation deleted" });
819
+ })
820
+ );
821
+ cmd.command("add-tag").description("Add a tag to a conversation").argument("<id>", "Conversation ID").argument("<tag>", "Tag name").action(
822
+ withErrorHandling(async (id, tag) => {
823
+ await client.addConversationTag(parseIdArg(id, "conversation"), tag);
824
+ outputJson({ message: `Tag "${tag}" added` });
825
+ })
826
+ );
827
+ cmd.command("remove-tag").description("Remove a tag from a conversation").argument("<id>", "Conversation ID").argument("<tag>", "Tag name").action(
828
+ withErrorHandling(async (id, tag) => {
829
+ await client.removeConversationTag(parseIdArg(id, "conversation"), tag);
830
+ outputJson({ message: `Tag "${tag}" removed` });
831
+ })
832
+ );
833
+ cmd.command("reply").description("Reply to a conversation").argument("<id>", "Conversation ID").requiredOption("--text <text>", "Reply text").option("--user <id>", "User ID sending the reply").option("--draft", "Save as draft").option("--status <status>", "Set conversation status after reply (active, closed, pending)").action(
834
+ withErrorHandling(
835
+ async (id, options) => {
836
+ await client.createReply(parseIdArg(id, "conversation"), {
837
+ text: options.text,
838
+ user: options.user ? parseIdArg(options.user, "user") : void 0,
839
+ draft: options.draft,
840
+ status: options.status
841
+ });
842
+ outputJson({ message: "Reply sent" });
843
+ }
844
+ )
845
+ );
846
+ cmd.command("note").description("Add a note to a conversation").argument("<id>", "Conversation ID").requiredOption("--text <text>", "Note text").option("--user <id>", "User ID adding the note").action(
847
+ withErrorHandling(
848
+ async (id, options) => {
849
+ await client.createNote(parseIdArg(id, "conversation"), {
850
+ text: options.text,
851
+ user: options.user ? parseIdArg(options.user, "user") : void 0
852
+ });
853
+ outputJson({ message: "Note added" });
854
+ }
855
+ )
856
+ );
799
857
  return cmd;
800
858
  }
801
859
 
@@ -803,52 +861,68 @@ function createConversationsCommand() {
803
861
  import { Command as Command4 } from "commander";
804
862
  function createCustomersCommand() {
805
863
  const cmd = new Command4("customers").description("Customer operations");
806
- cmd.command("list").description("List customers").option("-m, --mailbox <id>", "Filter by mailbox ID").option("--first-name <name>", "Filter by first name").option("--last-name <name>", "Filter by last name").option("--modified-since <date>", "Filter by modified date (ISO 8601)").option("--sort-field <field>", "Sort by field (createdAt, firstName, lastName, modifiedAt)").option("--sort-order <order>", "Sort order (asc, desc)").option("--page <number>", "Page number").option("-q, --query <query>", "Advanced search query").action(withErrorHandling(async (options) => {
807
- const result = await client.listCustomers({
808
- mailbox: options.mailbox,
809
- firstName: options.firstName,
810
- lastName: options.lastName,
811
- modifiedSince: options.modifiedSince,
812
- sortField: options.sortField,
813
- sortOrder: options.sortOrder,
814
- page: options.page ? parseInt(options.page, 10) : void 0,
815
- query: options.query
816
- });
817
- outputJson(result);
818
- }));
819
- cmd.command("view").description("View a customer").argument("<id>", "Customer ID").action(withErrorHandling(async (id) => {
820
- const customer = await client.getCustomer(parseIdArg(id, "customer"));
821
- outputJson(customer);
822
- }));
823
- cmd.command("create").description("Create a customer").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", "Email address").option("--phone <phone>", "Phone number").action(withErrorHandling(async (options) => {
824
- const data = {
825
- ...options.firstName && { firstName: options.firstName },
826
- ...options.lastName && { lastName: options.lastName },
827
- ...options.email && { emails: [{ type: "work", value: options.email }] },
828
- ...options.phone && { phones: [{ type: "work", value: options.phone }] }
829
- };
830
- requireAtLeastOneField(data, "Customer create");
831
- await client.createCustomer(data);
832
- outputJson({ message: "Customer created" });
833
- }));
834
- cmd.command("update").description("Update a customer").argument("<id>", "Customer ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--job-title <title>", "Job title").option("--location <location>", "Location").option("--organization <org>", "Organization").option("--background <text>", "Background notes").action(withErrorHandling(async (id, options) => {
835
- const data = {
836
- ...options.firstName && { firstName: options.firstName },
837
- ...options.lastName && { lastName: options.lastName },
838
- ...options.jobTitle && { jobTitle: options.jobTitle },
839
- ...options.location && { location: options.location },
840
- ...options.organization && { organization: options.organization },
841
- ...options.background && { background: options.background }
842
- };
843
- requireAtLeastOneField(data, "Customer update");
844
- await client.updateCustomer(parseIdArg(id, "customer"), data);
845
- outputJson({ message: "Customer updated" });
846
- }));
847
- cmd.command("delete").description("Delete a customer").argument("<id>", "Customer ID").option("-y, --yes", "Skip confirmation").action(withErrorHandling(async (id, options) => {
848
- await confirmDelete("customer", options.yes);
849
- await client.deleteCustomer(parseIdArg(id, "customer"));
850
- outputJson({ message: "Customer deleted" });
851
- }));
864
+ cmd.command("list").description("List customers").option("-m, --mailbox <id>", "Filter by mailbox ID").option("--first-name <name>", "Filter by first name").option("--last-name <name>", "Filter by last name").option("--modified-since <date>", "Filter by modified date (ISO 8601)").option("--sort-field <field>", "Sort by field (createdAt, firstName, lastName, modifiedAt)").option("--sort-order <order>", "Sort order (asc, desc)").option("--page <number>", "Page number").option("-q, --query <query>", "Advanced search query").action(
865
+ withErrorHandling(
866
+ async (options) => {
867
+ const result = await client.listCustomers({
868
+ mailbox: options.mailbox,
869
+ firstName: options.firstName,
870
+ lastName: options.lastName,
871
+ modifiedSince: options.modifiedSince,
872
+ sortField: options.sortField,
873
+ sortOrder: options.sortOrder,
874
+ page: options.page ? parseInt(options.page, 10) : void 0,
875
+ query: options.query
876
+ });
877
+ outputJson(result);
878
+ }
879
+ )
880
+ );
881
+ cmd.command("view").description("View a customer").argument("<id>", "Customer ID").action(
882
+ withErrorHandling(async (id) => {
883
+ const customer = await client.getCustomer(parseIdArg(id, "customer"));
884
+ outputJson(customer);
885
+ })
886
+ );
887
+ cmd.command("create").description("Create a customer").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", "Email address").option("--phone <phone>", "Phone number").action(
888
+ withErrorHandling(
889
+ async (options) => {
890
+ const data = {
891
+ ...options.firstName && { firstName: options.firstName },
892
+ ...options.lastName && { lastName: options.lastName },
893
+ ...options.email && { emails: [{ type: "work", value: options.email }] },
894
+ ...options.phone && { phones: [{ type: "work", value: options.phone }] }
895
+ };
896
+ requireAtLeastOneField(data, "Customer create");
897
+ await client.createCustomer(data);
898
+ outputJson({ message: "Customer created" });
899
+ }
900
+ )
901
+ );
902
+ cmd.command("update").description("Update a customer").argument("<id>", "Customer ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--job-title <title>", "Job title").option("--location <location>", "Location").option("--organization <org>", "Organization").option("--background <text>", "Background notes").action(
903
+ withErrorHandling(
904
+ async (id, options) => {
905
+ const data = {
906
+ ...options.firstName && { firstName: options.firstName },
907
+ ...options.lastName && { lastName: options.lastName },
908
+ ...options.jobTitle && { jobTitle: options.jobTitle },
909
+ ...options.location && { location: options.location },
910
+ ...options.organization && { organization: options.organization },
911
+ ...options.background && { background: options.background }
912
+ };
913
+ requireAtLeastOneField(data, "Customer update");
914
+ await client.updateCustomer(parseIdArg(id, "customer"), data);
915
+ outputJson({ message: "Customer updated" });
916
+ }
917
+ )
918
+ );
919
+ cmd.command("delete").description("Delete a customer").argument("<id>", "Customer ID").option("-y, --yes", "Skip confirmation").action(
920
+ withErrorHandling(async (id, options) => {
921
+ await confirmDelete("customer", options.yes);
922
+ await client.deleteCustomer(parseIdArg(id, "customer"));
923
+ outputJson({ message: "Customer deleted" });
924
+ })
925
+ );
852
926
  return cmd;
853
927
  }
854
928
 
@@ -856,14 +930,18 @@ function createCustomersCommand() {
856
930
  import { Command as Command5 } from "commander";
857
931
  function createTagsCommand() {
858
932
  const cmd = new Command5("tags").description("Tag operations");
859
- cmd.command("list").description("List all tags").option("--page <number>", "Page number").action(withErrorHandling(async (options) => {
860
- const result = await client.listTags(options.page ? parseInt(options.page, 10) : void 0);
861
- outputJson(result);
862
- }));
863
- cmd.command("view").description("View a tag").argument("<id>", "Tag ID").action(withErrorHandling(async (id) => {
864
- const tag = await client.getTag(parseIdArg(id, "tag"));
865
- outputJson(tag);
866
- }));
933
+ cmd.command("list").description("List all tags").option("--page <number>", "Page number").action(
934
+ withErrorHandling(async (options) => {
935
+ const result = await client.listTags(options.page ? parseInt(options.page, 10) : void 0);
936
+ outputJson(result);
937
+ })
938
+ );
939
+ cmd.command("view").description("View a tag").argument("<id>", "Tag ID").action(
940
+ withErrorHandling(async (id) => {
941
+ const tag = await client.getTag(parseIdArg(id, "tag"));
942
+ outputJson(tag);
943
+ })
944
+ );
867
945
  return cmd;
868
946
  }
869
947
 
@@ -871,33 +949,43 @@ function createTagsCommand() {
871
949
  import { Command as Command6 } from "commander";
872
950
  function createWorkflowsCommand() {
873
951
  const cmd = new Command6("workflows").description("Workflow operations");
874
- cmd.command("list").description("List workflows").option("-m, --mailbox <id>", "Filter by mailbox ID").option("-t, --type <type>", "Filter by type (manual, automatic)").option("--page <number>", "Page number").action(withErrorHandling(async (options) => {
875
- const result = await client.listWorkflows({
876
- mailbox: options.mailbox ? parseIdArg(options.mailbox, "mailbox") : void 0,
877
- type: options.type,
878
- page: options.page ? parseInt(options.page, 10) : void 0
879
- });
880
- outputJson(result);
881
- }));
882
- cmd.command("run").description("Run a manual workflow on conversations").argument("<workflow-id>", "Workflow ID").requiredOption("--conversations <ids>", "Comma-separated conversation IDs").action(withErrorHandling(async (workflowId, options) => {
883
- const conversationIds = options.conversations.split(",").map((id) => parseIdArg(id.trim(), "conversation"));
884
- await client.runWorkflow(parseIdArg(workflowId, "workflow"), conversationIds);
885
- outputJson({ message: "Workflow executed" });
886
- }));
887
- cmd.command("activate").description("Activate a workflow").argument("<id>", "Workflow ID").action(withErrorHandling(async (id) => {
888
- await client.updateWorkflowStatus(parseIdArg(id, "workflow"), "active");
889
- outputJson({ message: "Workflow activated" });
890
- }));
891
- cmd.command("deactivate").description("Deactivate a workflow").argument("<id>", "Workflow ID").action(withErrorHandling(async (id) => {
892
- await client.updateWorkflowStatus(parseIdArg(id, "workflow"), "inactive");
893
- outputJson({ message: "Workflow deactivated" });
894
- }));
952
+ cmd.command("list").description("List workflows").option("-m, --mailbox <id>", "Filter by mailbox ID").option("-t, --type <type>", "Filter by type (manual, automatic)").option("--page <number>", "Page number").action(
953
+ withErrorHandling(
954
+ async (options) => {
955
+ const result = await client.listWorkflows({
956
+ mailbox: options.mailbox ? parseIdArg(options.mailbox, "mailbox") : void 0,
957
+ type: options.type,
958
+ page: options.page ? parseInt(options.page, 10) : void 0
959
+ });
960
+ outputJson(result);
961
+ }
962
+ )
963
+ );
964
+ cmd.command("run").description("Run a manual workflow on conversations").argument("<workflow-id>", "Workflow ID").requiredOption("--conversations <ids>", "Comma-separated conversation IDs").action(
965
+ withErrorHandling(async (workflowId, options) => {
966
+ const conversationIds = options.conversations.split(",").map((id) => parseIdArg(id.trim(), "conversation"));
967
+ await client.runWorkflow(parseIdArg(workflowId, "workflow"), conversationIds);
968
+ outputJson({ message: "Workflow executed" });
969
+ })
970
+ );
971
+ cmd.command("activate").description("Activate a workflow").argument("<id>", "Workflow ID").action(
972
+ withErrorHandling(async (id) => {
973
+ await client.updateWorkflowStatus(parseIdArg(id, "workflow"), "active");
974
+ outputJson({ message: "Workflow activated" });
975
+ })
976
+ );
977
+ cmd.command("deactivate").description("Deactivate a workflow").argument("<id>", "Workflow ID").action(
978
+ withErrorHandling(async (id) => {
979
+ await client.updateWorkflowStatus(parseIdArg(id, "workflow"), "inactive");
980
+ outputJson({ message: "Workflow deactivated" });
981
+ })
982
+ );
895
983
  return cmd;
896
984
  }
897
985
 
898
986
  // src/cli.ts
899
987
  var program = new Command7();
900
- program.name("helpscout").description("A command-line interface for Help Scout").version("1.0.0").option("-c, --compact", "Minified JSON output (single line)").option("-p, --plain", "Strip HTML from body fields, output plain text").option("--include-metadata", "Include _links and _embedded in responses (stripped by default)").option("-f, --fields <fields>", "Comma-separated list of fields to include in output").hook("preAction", (thisCommand) => {
988
+ program.name("helpscout").description("A command-line interface for Help Scout").version("1.0.2").option("-c, --compact", "Minified JSON output (single line)").option("-p, --plain", "Strip HTML from body fields, output plain text").option("--include-metadata", "Include _links and _embedded in responses (stripped by default)").option("-f, --fields <fields>", "Comma-separated list of fields to include in output").hook("preAction", (thisCommand) => {
901
989
  const options = thisCommand.opts();
902
990
  setOutputOptions({
903
991
  compact: options.compact,
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/lib/errors.ts","../src/lib/api-client.ts","../src/lib/command-utils.ts","../src/commands/mailboxes.ts","../src/commands/conversations.ts","../src/commands/customers.ts","../src/commands/tags.ts","../src/commands/workflows.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createMailboxesCommand } from './commands/mailboxes.js';\nimport { createConversationsCommand } from './commands/conversations.js';\nimport { createCustomersCommand } from './commands/customers.js';\nimport { createTagsCommand } from './commands/tags.js';\nimport { createWorkflowsCommand } from './commands/workflows.js';\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name('helpscout')\n .description('A command-line interface for Help Scout')\n .version(__VERSION__)\n .option('-c, --compact', 'Minified JSON output (single line)')\n .option('-p, --plain', 'Strip HTML from body fields, output plain text')\n .option('--include-metadata', 'Include _links and _embedded in responses (stripped by default)')\n .option('-f, --fields <fields>', 'Comma-separated list of fields to include in output')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n slim: !options.includeMetadata,\n plain: options.plain,\n fields: options.fields,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createMailboxesCommand());\nprogram.addCommand(createConversationsCommand());\nprogram.addCommand(createCustomersCommand());\nprogram.addCommand(createTagsCommand());\nprogram.addCommand(createWorkflowsCommand());\n\nprogram.parseAsync().catch(() => {\n process.exit(1);\n});\n","import { convert } from 'html-to-text';\nimport type { OutputOptions } from '../types/index.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction htmlToPlainText(html: string): string {\n const text = convert(html, {\n wordwrap: false,\n preserveNewlines: false,\n selectors: [\n { selector: 'a', options: { ignoreHref: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n\n return text\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+/g, ' ')\n .trim();\n}\n\nfunction convertBodiesToPlainText(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(convertBodiesToPlainText);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key === 'body' && typeof value === 'string') {\n result[key] = htmlToPlainText(value);\n } else {\n result[key] = convertBodiesToPlainText(value);\n }\n }\n return result;\n }\n\n return data;\n}\n\nfunction stripMetadata(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(stripMetadata);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key === '_links' || key === '_embedded') {\n continue;\n }\n result[key] = stripMetadata(value);\n }\n return result;\n }\n\n return data;\n}\n\nfunction stripTagStyles(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(stripTagStyles);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n const isTag = 'id' in data && 'name' in data && 'slug' in data;\n\n for (const [key, value] of Object.entries(data)) {\n if (isTag && (key === 'color' || key === 'styles')) {\n continue;\n }\n result[key] = stripTagStyles(value);\n }\n return result;\n }\n\n return data;\n}\n\nfunction selectFields(data: unknown, fields: string[]): unknown {\n if (Array.isArray(data)) {\n return data.map(item => selectFields(item, fields));\n }\n\n if (isObject(data)) {\n const hasRequestedFields = fields.some(f => f in data);\n if (hasRequestedFields) {\n const result: Record<string, unknown> = {};\n for (const field of fields) {\n if (field in data) {\n result[field] = data[field];\n }\n }\n return result;\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n result[key] = selectFields(value, fields);\n }\n return result;\n }\n\n return data;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const mergedOptions = { ...globalOutputOptions, ...options };\n\n let processed = data;\n\n if (mergedOptions.slim) {\n processed = stripMetadata(processed);\n }\n\n if (mergedOptions.plain) {\n processed = convertBodiesToPlainText(processed);\n }\n\n processed = stripTagStyles(processed);\n\n if (mergedOptions.fields) {\n const fieldList = mergedOptions.fields.split(',').map(f => f.trim());\n processed = selectFields(processed, fieldList);\n }\n\n const jsonString = mergedOptions.compact\n ? JSON.stringify(processed)\n : JSON.stringify(processed, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication operations');\n\n cmd\n .command('login')\n .description('Configure Help Scout API credentials')\n .requiredOption('--app-id <id>', 'Help Scout App ID')\n .requiredOption('--app-secret <secret>', 'Help Scout App Secret')\n .action(withErrorHandling(async (options: { appId: string; appSecret: string }) => {\n await auth.setAppId(options.appId);\n await auth.setAppSecret(options.appSecret);\n\n client.clearToken();\n await client.refreshAccessToken();\n\n outputJson({ message: 'Successfully authenticated with Help Scout' });\n }));\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(withErrorHandling(async () => {\n await auth.logout();\n client.clearToken();\n outputJson({ message: 'Logged out successfully' });\n }));\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(withErrorHandling(async () => {\n const hasToken = await auth.isAuthenticated();\n const hasAppId = !!(await auth.getAppId());\n const hasAppSecret = !!(await auth.getAppSecret());\n\n outputJson({\n authenticated: hasToken,\n configured: hasAppId && hasAppSecret,\n });\n }));\n\n cmd\n .command('refresh')\n .description('Refresh access token')\n .action(withErrorHandling(async () => {\n client.clearToken();\n await client.refreshAccessToken();\n outputJson({ message: 'Access token refreshed' });\n }));\n\n return cmd;\n}\n","import { Entry } from '@napi-rs/keyring';\nimport { config } from './config.js';\n\nconst SERVICE_NAME = 'helpscout-cli';\nconst ACCESS_TOKEN_ACCOUNT = 'access-token';\nconst REFRESH_TOKEN_ACCOUNT = 'refresh-token';\nconst APP_ID_ACCOUNT = 'app-id';\nconst APP_SECRET_ACCOUNT = 'app-secret';\n\nconst KEYRING_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: npm install -g @stephendolan/helpscout-cli\\n' +\n 'Alternatively, use HELPSCOUT_APP_ID and HELPSCOUT_APP_SECRET environment variables.';\n\nconst keyringCache = new Map<string, Entry | null>();\n\nfunction getKeyring(account: string): Entry | null {\n if (keyringCache.has(account)) {\n return keyringCache.get(account)!;\n }\n try {\n const entry = new Entry(SERVICE_NAME, account);\n keyringCache.set(account, entry);\n return entry;\n } catch {\n keyringCache.set(account, null);\n return null;\n }\n}\n\nasync function getPassword(account: string): Promise<string | null> {\n const entry = getKeyring(account);\n if (entry) {\n try {\n return entry.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n}\n\nasync function setPassword(account: string, value: string): Promise<void> {\n const entry = getKeyring(account);\n if (!entry) {\n throw new Error(KEYRING_UNAVAILABLE_ERROR);\n }\n entry.setPassword(value);\n}\n\nasync function deletePassword(account: string): Promise<boolean> {\n const entry = getKeyring(account);\n if (entry) {\n return entry.deletePassword();\n }\n return false;\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n return getPassword(ACCESS_TOKEN_ACCOUNT);\n }\n\n async setAccessToken(token: string): Promise<void> {\n return setPassword(ACCESS_TOKEN_ACCOUNT, token);\n }\n\n async getRefreshToken(): Promise<string | null> {\n return getPassword(REFRESH_TOKEN_ACCOUNT);\n }\n\n async setRefreshToken(token: string): Promise<void> {\n return setPassword(REFRESH_TOKEN_ACCOUNT, token);\n }\n\n async getAppId(): Promise<string | null> {\n const keychainValue = await getPassword(APP_ID_ACCOUNT);\n return keychainValue || process.env.HELPSCOUT_APP_ID || null;\n }\n\n async setAppId(appId: string): Promise<void> {\n return setPassword(APP_ID_ACCOUNT, appId);\n }\n\n async getAppSecret(): Promise<string | null> {\n const keychainValue = await getPassword(APP_SECRET_ACCOUNT);\n return keychainValue || process.env.HELPSCOUT_APP_SECRET || null;\n }\n\n async setAppSecret(appSecret: string): Promise<void> {\n return setPassword(APP_SECRET_ACCOUNT, appSecret);\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await deletePassword(ACCESS_TOKEN_ACCOUNT);\n await deletePassword(REFRESH_TOKEN_ACCOUNT);\n config.clearDefaultMailbox();\n }\n\n async clearAll(): Promise<void> {\n await deletePassword(ACCESS_TOKEN_ACCOUNT);\n await deletePassword(REFRESH_TOKEN_ACCOUNT);\n await deletePassword(APP_ID_ACCOUNT);\n await deletePassword(APP_SECRET_ACCOUNT);\n config.clear();\n }\n}\n\nexport const auth = new AuthManager();\n","import Conf from 'conf';\n\ninterface ConfigSchema {\n defaultMailbox?: string;\n}\n\nconst store = new Conf<ConfigSchema>({\n projectName: 'helpscout-cli',\n});\n\nexport const config = {\n getDefaultMailbox(): string | undefined {\n return store.get('defaultMailbox') || process.env.HELPSCOUT_MAILBOX_ID;\n },\n\n setDefaultMailbox(mailboxId: string): void {\n store.set('defaultMailbox', mailboxId);\n },\n\n clearDefaultMailbox(): void {\n store.delete('defaultMailbox');\n },\n\n clear(): void {\n store.clear();\n },\n};\n","import type { HelpScoutError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class HelpScoutCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = 'HelpScoutCliError';\n }\n}\n\nexport class HelpScoutApiError extends Error {\n constructor(\n message: string,\n public apiError: unknown,\n public statusCode: number,\n ) {\n super(message);\n this.name = 'HelpScoutApiError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n unauthorized: 401,\n forbidden: 403,\n not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /client[_-]?secret[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface ApiErrorResponse {\n error?: string;\n error_description?: string;\n message?: string;\n _embedded?: {\n errors?: Array<{\n path?: string;\n message?: string;\n rejectedValue?: string;\n }>;\n };\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): HelpScoutError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n };\n }\n\n const apiError = error as ApiErrorResponse;\n\n let detail = 'An error occurred';\n if (apiError.error_description) {\n detail = apiError.error_description;\n } else if (apiError.message) {\n detail = apiError.message;\n } else if (apiError._embedded?.errors?.length) {\n detail = apiError._embedded.errors\n .map(e => e.message || e.path)\n .filter(Boolean)\n .join('; ');\n }\n\n return {\n name: apiError.error || 'api_error',\n detail: sanitizeErrorMessage(detail),\n };\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const hint = name === 'too_many_requests'\n ? 'Help Scout API limit: 200 requests/minute. Wait a moment and retry.'\n : undefined;\n\n const response: { error: { name: string; detail: string; statusCode: number }; hint?: string } = {\n error: { name, detail, statusCode },\n };\n\n if (hint) {\n response.hint = hint;\n }\n\n outputJson(response);\n process.exit(1);\n}\n\nexport function handleHelpScoutError(error: unknown): never {\n if (error instanceof HelpScoutCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n if (error instanceof HelpScoutApiError) {\n const hsError: HelpScoutError = sanitizeApiError(error.apiError);\n formatErrorResponse(\n hsError.name,\n hsError.detail,\n error.statusCode || ERROR_STATUS_CODES[hsError.name] || 500,\n );\n }\n\n if (error instanceof Error) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('unknown_error', sanitized, 1);\n }\n\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n}\n","import { auth } from './auth.js';\nimport { HelpScoutCliError, HelpScoutApiError } from './errors.js';\nimport dotenv from 'dotenv';\nimport type {\n Conversation,\n Customer,\n Tag,\n Workflow,\n Mailbox,\n Thread,\n PageInfo,\n} from '../types/index.js';\n\ndotenv.config();\n\nconst API_BASE = 'https://api.helpscout.net/v2';\nconst TOKEN_URL = 'https://api.helpscout.net/v2/oauth2/token';\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n token_type: string;\n expires_in: number;\n}\n\ninterface PaginatedResponse<T> {\n _embedded: T;\n page: PageInfo;\n}\n\nexport class HelpScoutClient {\n private accessToken: string | null = null;\n\n clearToken(): void {\n this.accessToken = null;\n }\n\n async refreshAccessToken(): Promise<string> {\n const appId = await auth.getAppId();\n const appSecret = await auth.getAppSecret();\n const refreshToken = await auth.getRefreshToken();\n\n if (!appId || !appSecret) {\n throw new HelpScoutCliError(\n 'Not configured. Please run: helpscout auth login',\n 401,\n );\n }\n\n if (refreshToken) {\n try {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: appId,\n client_secret: appSecret,\n refresh_token: refreshToken,\n }),\n });\n\n if (response.ok) {\n const data = (await response.json()) as TokenResponse;\n await auth.setAccessToken(data.access_token);\n if (data.refresh_token) {\n await auth.setRefreshToken(data.refresh_token);\n }\n this.accessToken = data.access_token;\n return data.access_token;\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(JSON.stringify({ warning: 'Refresh token failed, using client credentials', reason: message }));\n }\n }\n\n let response: Response;\n try {\n response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: appId,\n client_secret: appSecret,\n }),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown network error';\n throw new HelpScoutCliError(`Network request failed during authentication: ${message}`, 0);\n }\n\n if (!response.ok) {\n const error = await response.json();\n throw new HelpScoutApiError('OAuth token request failed', error, response.status);\n }\n\n const data = (await response.json()) as TokenResponse;\n await auth.setAccessToken(data.access_token);\n this.accessToken = data.access_token;\n return data.access_token;\n }\n\n async getAccessToken(): Promise<string> {\n if (this.accessToken) {\n return this.accessToken;\n }\n\n const storedToken = await auth.getAccessToken();\n if (storedToken) {\n this.accessToken = storedToken;\n return storedToken;\n }\n\n return this.refreshAccessToken();\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: {\n params?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n retry?: boolean;\n rateLimitRetry?: boolean;\n } = {},\n ): Promise<T> {\n const { params, body, retry = true, rateLimitRetry = true } = options;\n\n const url = new URL(`${API_BASE}${path}`);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n\n const token = await this.getAccessToken();\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n };\n if (body) {\n fetchOptions.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url.toString(), fetchOptions);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown network error';\n throw new HelpScoutCliError(`Network request failed: ${message}`, 0);\n }\n\n if (response.status === 401 && retry) {\n this.accessToken = null;\n await this.refreshAccessToken();\n return this.request(method, path, { ...options, retry: false });\n }\n\n if (response.status === 429 && rateLimitRetry) {\n const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);\n const waitSeconds = Math.min(retryAfter, 120);\n console.error(JSON.stringify({ warning: `Rate limited. Waiting ${waitSeconds}s before retry...` }));\n await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));\n return this.request(method, path, { ...options, rateLimitRetry: false });\n }\n\n if (response.status === 204) {\n return {} as T;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new HelpScoutApiError('API request failed', error, response.status);\n }\n\n return response.json() as Promise<T>;\n }\n\n\n // Conversations\n async listConversations(params: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: number;\n embed?: string;\n query?: string;\n } = {}) {\n const response = await this.request<PaginatedResponse<{ conversations: Conversation[] }>>(\n 'GET',\n '/conversations',\n { params },\n );\n return {\n conversations: response._embedded?.conversations || [],\n page: response.page,\n };\n }\n\n async listAllConversations(params: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n query?: string;\n } = {}): Promise<Conversation[]> {\n const allConversations: Conversation[] = [];\n let page = 1;\n let totalPages = 1;\n\n do {\n const result = await this.listConversations({ ...params, page });\n allConversations.push(...result.conversations);\n totalPages = result.page.totalPages;\n page++;\n } while (page <= totalPages);\n\n return allConversations;\n }\n\n async getConversation(conversationId: number, embed?: string) {\n const params = embed ? { embed } : undefined;\n return this.request<Conversation>('GET', `/conversations/${conversationId}`, { params });\n }\n\n async getConversationThreads(conversationId: number) {\n const response = await this.request<PaginatedResponse<{ threads: Thread[] }>>(\n 'GET',\n `/conversations/${conversationId}/threads`,\n );\n return response._embedded?.threads || [];\n }\n\n async updateConversation(\n conversationId: number,\n data: Partial<{\n op: string;\n path: string;\n value: unknown;\n }>,\n ) {\n await this.request<void>('PATCH', `/conversations/${conversationId}`, { body: data });\n }\n\n async deleteConversation(conversationId: number) {\n await this.request<void>('DELETE', `/conversations/${conversationId}`);\n }\n\n async addConversationTag(conversationId: number, tag: string) {\n await this.request<void>('PUT', `/conversations/${conversationId}/tags`, {\n body: { tags: [tag] },\n });\n }\n\n async removeConversationTag(conversationId: number, tag: string) {\n const conversation = await this.getConversation(conversationId);\n const existingTags = conversation?.tags?.map(t => t.name) || [];\n const newTags = existingTags.filter(t => t !== tag);\n await this.request<void>('PUT', `/conversations/${conversationId}/tags`, {\n body: { tags: newTags },\n });\n }\n\n async createReply(\n conversationId: number,\n data: {\n text: string;\n user?: number;\n draft?: boolean;\n status?: string;\n },\n ) {\n await this.request<void>('POST', `/conversations/${conversationId}/reply`, { body: data });\n }\n\n async createNote(\n conversationId: number,\n data: {\n text: string;\n user?: number;\n },\n ) {\n await this.request<void>('POST', `/conversations/${conversationId}/notes`, { body: data });\n }\n\n // Customers\n async listCustomers(params: {\n mailbox?: string;\n firstName?: string;\n lastName?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: number;\n query?: string;\n } = {}) {\n const response = await this.request<PaginatedResponse<{ customers: Customer[] }>>(\n 'GET',\n '/customers',\n { params },\n );\n return {\n customers: response._embedded?.customers || [],\n page: response.page,\n };\n }\n\n async getCustomer(customerId: number) {\n return this.request<Customer>('GET', `/customers/${customerId}`);\n }\n\n async createCustomer(data: {\n firstName?: string;\n lastName?: string;\n emails?: Array<{ type: string; value: string }>;\n phones?: Array<{ type: string; value: string }>;\n }) {\n await this.request<void>('POST', '/customers', { body: data });\n }\n\n async updateCustomer(\n customerId: number,\n data: Partial<{\n firstName: string;\n lastName: string;\n jobTitle: string;\n location: string;\n organization: string;\n background: string;\n }>,\n ) {\n await this.request<void>('PUT', `/customers/${customerId}`, { body: data });\n }\n\n async deleteCustomer(customerId: number) {\n await this.request<void>('DELETE', `/customers/${customerId}`);\n }\n\n // Tags\n async listTags(page?: number) {\n const response = await this.request<PaginatedResponse<{ tags: Tag[] }>>(\n 'GET',\n '/tags',\n { params: page ? { page } : undefined },\n );\n return {\n tags: response._embedded?.tags || [],\n page: response.page,\n };\n }\n\n async getTag(tagId: number) {\n return this.request<Tag>('GET', `/tags/${tagId}`);\n }\n\n // Workflows\n async listWorkflows(params: {\n mailbox?: number;\n type?: string;\n page?: number;\n } = {}) {\n const response = await this.request<PaginatedResponse<{ workflows: Workflow[] }>>(\n 'GET',\n '/workflows',\n { params: { mailboxId: params.mailbox, type: params.type, page: params.page } },\n );\n return {\n workflows: response._embedded?.workflows || [],\n page: response.page,\n };\n }\n\n async runWorkflow(workflowId: number, conversationIds: number[]) {\n await this.request<void>('POST', `/workflows/${workflowId}/run`, {\n body: { conversationIds },\n });\n }\n\n async updateWorkflowStatus(workflowId: number, status: 'active' | 'inactive') {\n await this.request<void>('PATCH', `/workflows/${workflowId}`, {\n body: { op: 'replace', path: '/status', value: status },\n });\n }\n\n // Mailboxes\n async listMailboxes(page?: number) {\n const response = await this.request<PaginatedResponse<{ mailboxes: Mailbox[] }>>(\n 'GET',\n '/mailboxes',\n { params: page ? { page } : undefined },\n );\n return {\n mailboxes: response._embedded?.mailboxes || [],\n page: response.page,\n };\n }\n\n async getMailbox(mailboxId: number) {\n return this.request<Mailbox>('GET', `/mailboxes/${mailboxId}`);\n }\n}\n\nexport const client = new HelpScoutClient();\n","import { handleHelpScoutError, HelpScoutCliError } from './errors.js';\nimport { outputJson } from './output.js';\n\nexport function withErrorHandling<T extends unknown[], R>(\n fn: (...args: T) => Promise<R>,\n): (...args: T) => Promise<void> {\n return async (...args: T) => {\n try {\n await fn(...args);\n } catch (error) {\n handleHelpScoutError(error);\n }\n };\n}\n\nexport function parseIdArg(value: string, resourceType: string = 'resource'): number {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed) || parsed <= 0) {\n throw new HelpScoutCliError(`Invalid ${resourceType} ID: \"${value}\"`, 400);\n }\n return parsed;\n}\n\nexport function requireAtLeastOneField(\n data: Record<string, unknown>,\n operation: string,\n): void {\n const hasFields = Object.values(data).some((v) => v !== undefined);\n if (!hasFields) {\n throw new HelpScoutCliError(`${operation} requires at least one field to update`, 400);\n }\n}\n\nexport async function confirmDelete(\n resourceType: string,\n skipConfirmation?: boolean,\n): Promise<boolean> {\n if (skipConfirmation) {\n return true;\n }\n\n const readline = await import('readline');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(`Delete ${resourceType}? (y/N) `, (answer) => {\n rl.close();\n if (answer.toLowerCase() !== 'y') {\n outputJson({ cancelled: true, message: 'Deletion cancelled' });\n process.exit(0);\n }\n resolve(true);\n });\n });\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createMailboxesCommand(): Command {\n const cmd = new Command('mailboxes').description('Mailbox operations');\n\n cmd\n .command('list')\n .description('List mailboxes')\n .option('--page <number>', 'Page number')\n .action(withErrorHandling(async (options: { page?: string }) => {\n const result = await client.listMailboxes(options.page ? parseInt(options.page, 10) : undefined);\n outputJson(result);\n }));\n\n cmd\n .command('view')\n .description('View a mailbox')\n .argument('<id>', 'Mailbox ID')\n .action(withErrorHandling(async (id: string) => {\n const mailbox = await client.getMailbox(parseIdArg(id, 'mailbox'));\n outputJson(mailbox);\n }));\n\n cmd\n .command('set-default')\n .description('Set default mailbox')\n .argument('<id>', 'Mailbox ID')\n .action(withErrorHandling(async (id: string) => {\n const mailboxId = parseIdArg(id, 'mailbox');\n config.setDefaultMailbox(String(mailboxId));\n outputJson({ message: `Default mailbox set to ${mailboxId}` });\n }));\n\n cmd\n .command('get-default')\n .description('Get default mailbox')\n .action(withErrorHandling(async () => {\n const mailboxId = config.getDefaultMailbox();\n outputJson({ defaultMailbox: mailboxId || null });\n }));\n\n cmd\n .command('clear-default')\n .description('Clear default mailbox')\n .action(withErrorHandling(async () => {\n config.clearDefaultMailbox();\n outputJson({ message: 'Default mailbox cleared' });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, confirmDelete, parseIdArg } from '../lib/command-utils.js';\nimport type { Conversation } from '../types/index.js';\n\ninterface ConversationSummary {\n total: number;\n byStatus: Record<string, number>;\n byTag: Record<string, number>;\n conversations: Array<{\n id: number;\n subject: string;\n status: string;\n tags: string[];\n preview: string;\n }>;\n}\n\nfunction summarizeConversations(conversations: Conversation[]): ConversationSummary {\n const byStatus: Record<string, number> = {};\n const byTag: Record<string, number> = {};\n\n for (const conv of conversations) {\n byStatus[conv.status] = (byStatus[conv.status] || 0) + 1;\n\n for (const tag of conv.tags || []) {\n byTag[tag.name] = (byTag[tag.name] || 0) + 1;\n }\n }\n\n return {\n total: conversations.length,\n byStatus,\n byTag,\n conversations: conversations.map(c => ({\n id: c.id,\n subject: c.subject,\n status: c.status,\n tags: (c.tags || []).map(t => t.name),\n preview: c.preview,\n })),\n };\n}\n\nexport function createConversationsCommand(): Command {\n const cmd = new Command('conversations').description('Conversation operations');\n\n cmd\n .command('list')\n .description('List conversations')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('-s, --status <status>', 'Filter by status (active, all, closed, open, pending, spam)')\n .option('-t, --tag <tags>', 'Filter by tag(s), comma-separated')\n .option('--assigned-to <id>', 'Filter by assignee user ID')\n .option('--modified-since <date>', 'Filter by modified date (ISO 8601)')\n .option('--sort-field <field>', 'Sort by field (createdAt, modifiedAt, number, status, subject)')\n .option('--sort-order <order>', 'Sort order (asc, desc)')\n .option('--page <number>', 'Page number')\n .option('--embed <resources>', 'Embed resources (threads)')\n .option('-q, --query <query>', 'Advanced search query (see https://docs.helpscout.com/article/47-search-filters-with-operators)')\n .option('--summary', 'Output aggregated summary instead of full conversation list')\n .action(withErrorHandling(async (options: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: string;\n embed?: string;\n query?: string;\n summary?: boolean;\n }) => {\n if (options.summary) {\n const allConversations = await client.listAllConversations({\n mailbox: options.mailbox,\n status: options.status,\n tag: options.tag,\n assignedTo: options.assignedTo,\n modifiedSince: options.modifiedSince,\n query: options.query,\n });\n const summary = summarizeConversations(allConversations);\n outputJson(summary);\n return;\n }\n\n const result = await client.listConversations({\n mailbox: options.mailbox,\n status: options.status,\n tag: options.tag,\n assignedTo: options.assignedTo,\n modifiedSince: options.modifiedSince,\n sortField: options.sortField,\n sortOrder: options.sortOrder,\n page: options.page ? parseInt(options.page, 10) : undefined,\n embed: options.embed,\n query: options.query,\n });\n outputJson(result);\n }));\n\n cmd\n .command('view')\n .description('View a conversation')\n .argument('<id>', 'Conversation ID')\n .option('--embed <resources>', 'Embed resources (threads)')\n .action(withErrorHandling(async (id: string, options: { embed?: string }) => {\n const conversation = await client.getConversation(parseIdArg(id, 'conversation'), options.embed);\n outputJson(conversation);\n }));\n\n cmd\n .command('threads')\n .description('List threads for a conversation (defaults to email communications only)')\n .argument('<id>', 'Conversation ID')\n .option('--include-notes', 'Include internal notes')\n .option('--all', 'Show all thread types including lineitems, workflows, etc.')\n .option('-t, --type <types>', 'Filter by specific thread type(s), comma-separated (customer, message, note, lineitem, chat, phone, forwardchild, forwardparent, beaconchat)')\n .action(withErrorHandling(async (id: string, options: { includeNotes?: boolean; all?: boolean; type?: string }) => {\n let threads = await client.getConversationThreads(parseIdArg(id, 'conversation'));\n\n if (options.type) {\n const types = options.type.split(',').map(t => t.trim().toLowerCase());\n threads = threads.filter(t => types.includes(t.type));\n } else if (!options.all) {\n const allowedTypes = options.includeNotes\n ? ['customer', 'message', 'note', 'chat', 'phone']\n : ['customer', 'message', 'chat', 'phone'];\n threads = threads.filter(t => allowedTypes.includes(t.type));\n }\n\n outputJson(threads);\n }));\n\n cmd\n .command('delete')\n .description('Delete a conversation')\n .argument('<id>', 'Conversation ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { yes?: boolean }) => {\n await confirmDelete('conversation', options.yes);\n await client.deleteConversation(parseIdArg(id, 'conversation'));\n outputJson({ message: 'Conversation deleted' });\n }));\n\n cmd\n .command('add-tag')\n .description('Add a tag to a conversation')\n .argument('<id>', 'Conversation ID')\n .argument('<tag>', 'Tag name')\n .action(withErrorHandling(async (id: string, tag: string) => {\n await client.addConversationTag(parseIdArg(id, 'conversation'), tag);\n outputJson({ message: `Tag \"${tag}\" added` });\n }));\n\n cmd\n .command('remove-tag')\n .description('Remove a tag from a conversation')\n .argument('<id>', 'Conversation ID')\n .argument('<tag>', 'Tag name')\n .action(withErrorHandling(async (id: string, tag: string) => {\n await client.removeConversationTag(parseIdArg(id, 'conversation'), tag);\n outputJson({ message: `Tag \"${tag}\" removed` });\n }));\n\n cmd\n .command('reply')\n .description('Reply to a conversation')\n .argument('<id>', 'Conversation ID')\n .requiredOption('--text <text>', 'Reply text')\n .option('--user <id>', 'User ID sending the reply')\n .option('--draft', 'Save as draft')\n .option('--status <status>', 'Set conversation status after reply (active, closed, pending)')\n .action(withErrorHandling(async (id: string, options: {\n text: string;\n user?: string;\n draft?: boolean;\n status?: string;\n }) => {\n await client.createReply(parseIdArg(id, 'conversation'), {\n text: options.text,\n user: options.user ? parseIdArg(options.user, 'user') : undefined,\n draft: options.draft,\n status: options.status,\n });\n outputJson({ message: 'Reply sent' });\n }));\n\n cmd\n .command('note')\n .description('Add a note to a conversation')\n .argument('<id>', 'Conversation ID')\n .requiredOption('--text <text>', 'Note text')\n .option('--user <id>', 'User ID adding the note')\n .action(withErrorHandling(async (id: string, options: {\n text: string;\n user?: string;\n }) => {\n await client.createNote(parseIdArg(id, 'conversation'), {\n text: options.text,\n user: options.user ? parseIdArg(options.user, 'user') : undefined,\n });\n outputJson({ message: 'Note added' });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, confirmDelete, parseIdArg, requireAtLeastOneField } from '../lib/command-utils.js';\n\nexport function createCustomersCommand(): Command {\n const cmd = new Command('customers').description('Customer operations');\n\n cmd\n .command('list')\n .description('List customers')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('--first-name <name>', 'Filter by first name')\n .option('--last-name <name>', 'Filter by last name')\n .option('--modified-since <date>', 'Filter by modified date (ISO 8601)')\n .option('--sort-field <field>', 'Sort by field (createdAt, firstName, lastName, modifiedAt)')\n .option('--sort-order <order>', 'Sort order (asc, desc)')\n .option('--page <number>', 'Page number')\n .option('-q, --query <query>', 'Advanced search query')\n .action(withErrorHandling(async (options: {\n mailbox?: string;\n firstName?: string;\n lastName?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: string;\n query?: string;\n }) => {\n const result = await client.listCustomers({\n mailbox: options.mailbox,\n firstName: options.firstName,\n lastName: options.lastName,\n modifiedSince: options.modifiedSince,\n sortField: options.sortField,\n sortOrder: options.sortOrder,\n page: options.page ? parseInt(options.page, 10) : undefined,\n query: options.query,\n });\n outputJson(result);\n }));\n\n cmd\n .command('view')\n .description('View a customer')\n .argument('<id>', 'Customer ID')\n .action(withErrorHandling(async (id: string) => {\n const customer = await client.getCustomer(parseIdArg(id, 'customer'));\n outputJson(customer);\n }));\n\n cmd\n .command('create')\n .description('Create a customer')\n .option('--first-name <name>', 'First name')\n .option('--last-name <name>', 'Last name')\n .option('--email <email>', 'Email address')\n .option('--phone <phone>', 'Phone number')\n .action(withErrorHandling(async (options: {\n firstName?: string;\n lastName?: string;\n email?: string;\n phone?: string;\n }) => {\n const data = {\n ...(options.firstName && { firstName: options.firstName }),\n ...(options.lastName && { lastName: options.lastName }),\n ...(options.email && { emails: [{ type: 'work', value: options.email }] }),\n ...(options.phone && { phones: [{ type: 'work', value: options.phone }] }),\n };\n requireAtLeastOneField(data, 'Customer create');\n await client.createCustomer(data);\n outputJson({ message: 'Customer created' });\n }));\n\n cmd\n .command('update')\n .description('Update a customer')\n .argument('<id>', 'Customer ID')\n .option('--first-name <name>', 'First name')\n .option('--last-name <name>', 'Last name')\n .option('--job-title <title>', 'Job title')\n .option('--location <location>', 'Location')\n .option('--organization <org>', 'Organization')\n .option('--background <text>', 'Background notes')\n .action(withErrorHandling(async (id: string, options: {\n firstName?: string;\n lastName?: string;\n jobTitle?: string;\n location?: string;\n organization?: string;\n background?: string;\n }) => {\n const data = {\n ...(options.firstName && { firstName: options.firstName }),\n ...(options.lastName && { lastName: options.lastName }),\n ...(options.jobTitle && { jobTitle: options.jobTitle }),\n ...(options.location && { location: options.location }),\n ...(options.organization && { organization: options.organization }),\n ...(options.background && { background: options.background }),\n };\n requireAtLeastOneField(data, 'Customer update');\n await client.updateCustomer(parseIdArg(id, 'customer'), data);\n outputJson({ message: 'Customer updated' });\n }));\n\n cmd\n .command('delete')\n .description('Delete a customer')\n .argument('<id>', 'Customer ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { yes?: boolean }) => {\n await confirmDelete('customer', options.yes);\n await client.deleteCustomer(parseIdArg(id, 'customer'));\n outputJson({ message: 'Customer deleted' });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createTagsCommand(): Command {\n const cmd = new Command('tags').description('Tag operations');\n\n cmd\n .command('list')\n .description('List all tags')\n .option('--page <number>', 'Page number')\n .action(withErrorHandling(async (options: { page?: string }) => {\n const result = await client.listTags(options.page ? parseInt(options.page, 10) : undefined);\n outputJson(result);\n }));\n\n cmd\n .command('view')\n .description('View a tag')\n .argument('<id>', 'Tag ID')\n .action(withErrorHandling(async (id: string) => {\n const tag = await client.getTag(parseIdArg(id, 'tag'));\n outputJson(tag);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createWorkflowsCommand(): Command {\n const cmd = new Command('workflows').description('Workflow operations');\n\n cmd\n .command('list')\n .description('List workflows')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('-t, --type <type>', 'Filter by type (manual, automatic)')\n .option('--page <number>', 'Page number')\n .action(withErrorHandling(async (options: {\n mailbox?: string;\n type?: string;\n page?: string;\n }) => {\n const result = await client.listWorkflows({\n mailbox: options.mailbox ? parseIdArg(options.mailbox, 'mailbox') : undefined,\n type: options.type,\n page: options.page ? parseInt(options.page, 10) : undefined,\n });\n outputJson(result);\n }));\n\n cmd\n .command('run')\n .description('Run a manual workflow on conversations')\n .argument('<workflow-id>', 'Workflow ID')\n .requiredOption('--conversations <ids>', 'Comma-separated conversation IDs')\n .action(withErrorHandling(async (workflowId: string, options: { conversations: string }) => {\n const conversationIds = options.conversations.split(',').map(id => parseIdArg(id.trim(), 'conversation'));\n await client.runWorkflow(parseIdArg(workflowId, 'workflow'), conversationIds);\n outputJson({ message: 'Workflow executed' });\n }));\n\n cmd\n .command('activate')\n .description('Activate a workflow')\n .argument('<id>', 'Workflow ID')\n .action(withErrorHandling(async (id: string) => {\n await client.updateWorkflowStatus(parseIdArg(id, 'workflow'), 'active');\n outputJson({ message: 'Workflow activated' });\n }));\n\n cmd\n .command('deactivate')\n .description('Deactivate a workflow')\n .argument('<id>', 'Workflow ID')\n .action(withErrorHandling(async (id: string) => {\n await client.updateWorkflowStatus(parseIdArg(id, 'workflow'), 'inactive');\n outputJson({ message: 'Workflow deactivated' });\n }));\n\n return cmd;\n}\n"],"mappings":";;;AAEA,SAAS,WAAAA,gBAAe;;;ACFxB,SAAS,eAAe;AAGxB,IAAI,sBAAqC,CAAC;AAEnC,SAAS,iBAAiB,SAA8B;AAC7D,wBAAsB;AACxB;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,QAAM,OAAO,QAAQ,MAAM;AAAA,IACzB,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,WAAW;AAAA,MACT,EAAE,UAAU,KAAK,SAAS,EAAE,YAAY,KAAK,EAAE;AAAA,MAC/C,EAAE,UAAU,OAAO,QAAQ,OAAO;AAAA,IACpC;AAAA,EACF,CAAC;AAED,SAAO,KACJ,QAAQ,WAAW,MAAM,EACzB,QAAQ,WAAW,GAAG,EACtB,KAAK;AACV;AAEA,SAAS,yBAAyB,MAAwB;AACxD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,wBAAwB;AAAA,EAC1C;AAEA,MAAI,SAAS,IAAI,GAAG;AAClB,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,QAAQ,UAAU,OAAO,UAAU,UAAU;AAC/C,eAAO,GAAG,IAAI,gBAAgB,KAAK;AAAA,MACrC,OAAO;AACL,eAAO,GAAG,IAAI,yBAAyB,KAAK;AAAA,MAC9C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,MAAwB;AAC7C,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B;AAEA,MAAI,SAAS,IAAI,GAAG;AAClB,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,QAAQ,YAAY,QAAQ,aAAa;AAC3C;AAAA,MACF;AACA,aAAO,GAAG,IAAI,cAAc,KAAK;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,MAAwB;AAC9C,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,cAAc;AAAA,EAChC;AAEA,MAAI,SAAS,IAAI,GAAG;AAClB,UAAM,SAAkC,CAAC;AACzC,UAAM,QAAQ,QAAQ,QAAQ,UAAU,QAAQ,UAAU;AAE1D,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,UAAU,QAAQ,WAAW,QAAQ,WAAW;AAClD;AAAA,MACF;AACA,aAAO,GAAG,IAAI,eAAe,KAAK;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,aAAa,MAAe,QAA2B;AAC9D,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,UAAQ,aAAa,MAAM,MAAM,CAAC;AAAA,EACpD;AAEA,MAAI,SAAS,IAAI,GAAG;AAClB,UAAM,qBAAqB,OAAO,KAAK,OAAK,KAAK,IAAI;AACrD,QAAI,oBAAoB;AACtB,YAAMC,UAAkC,CAAC;AACzC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,SAAS,MAAM;AACjB,UAAAA,QAAO,KAAK,IAAI,KAAK,KAAK;AAAA,QAC5B;AAAA,MACF;AACA,aAAOA;AAAA,IACT;AAEA,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,aAAO,GAAG,IAAI,aAAa,OAAO,MAAM;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,WAAW,MAAe,UAAyB,CAAC,GAAS;AAC3E,QAAM,gBAAgB,EAAE,GAAG,qBAAqB,GAAG,QAAQ;AAE3D,MAAI,YAAY;AAEhB,MAAI,cAAc,MAAM;AACtB,gBAAY,cAAc,SAAS;AAAA,EACrC;AAEA,MAAI,cAAc,OAAO;AACvB,gBAAY,yBAAyB,SAAS;AAAA,EAChD;AAEA,cAAY,eAAe,SAAS;AAEpC,MAAI,cAAc,QAAQ;AACxB,UAAM,YAAY,cAAc,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AACnE,gBAAY,aAAa,WAAW,SAAS;AAAA,EAC/C;AAEA,QAAM,aAAa,cAAc,UAC7B,KAAK,UAAU,SAAS,IACxB,KAAK,UAAU,WAAW,MAAM,CAAC;AAErC,UAAQ,IAAI,UAAU;AACxB;;;AC7IA,SAAS,eAAe;;;ACAxB,SAAS,aAAa;;;ACAtB,OAAO,UAAU;AAMjB,IAAM,QAAQ,IAAI,KAAmB;AAAA,EACnC,aAAa;AACf,CAAC;AAEM,IAAM,SAAS;AAAA,EACpB,oBAAwC;AACtC,WAAO,MAAM,IAAI,gBAAgB,KAAK,QAAQ,IAAI;AAAA,EACpD;AAAA,EAEA,kBAAkB,WAAyB;AACzC,UAAM,IAAI,kBAAkB,SAAS;AAAA,EACvC;AAAA,EAEA,sBAA4B;AAC1B,UAAM,OAAO,gBAAgB;AAAA,EAC/B;AAAA,EAEA,QAAc;AACZ,UAAM,MAAM;AAAA,EACd;AACF;;;ADvBA,IAAM,eAAe;AACrB,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAE3B,IAAM,4BACJ;AAKF,IAAM,eAAe,oBAAI,IAA0B;AAEnD,SAAS,WAAW,SAA+B;AACjD,MAAI,aAAa,IAAI,OAAO,GAAG;AAC7B,WAAO,aAAa,IAAI,OAAO;AAAA,EACjC;AACA,MAAI;AACF,UAAM,QAAQ,IAAI,MAAM,cAAc,OAAO;AAC7C,iBAAa,IAAI,SAAS,KAAK;AAC/B,WAAO;AAAA,EACT,QAAQ;AACN,iBAAa,IAAI,SAAS,IAAI;AAC9B,WAAO;AAAA,EACT;AACF;AAEA,eAAe,YAAY,SAAyC;AAClE,QAAM,QAAQ,WAAW,OAAO;AAChC,MAAI,OAAO;AACT,QAAI;AACF,aAAO,MAAM,YAAY;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,YAAY,SAAiB,OAA8B;AACxE,QAAM,QAAQ,WAAW,OAAO;AAChC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACA,QAAM,YAAY,KAAK;AACzB;AAEA,eAAe,eAAe,SAAmC;AAC/D,QAAM,QAAQ,WAAW,OAAO;AAChC,MAAI,OAAO;AACT,WAAO,MAAM,eAAe;AAAA,EAC9B;AACA,SAAO;AACT;AAEO,IAAM,cAAN,MAAkB;AAAA,EACvB,MAAM,iBAAyC;AAC7C,WAAO,YAAY,oBAAoB;AAAA,EACzC;AAAA,EAEA,MAAM,eAAe,OAA8B;AACjD,WAAO,YAAY,sBAAsB,KAAK;AAAA,EAChD;AAAA,EAEA,MAAM,kBAA0C;AAC9C,WAAO,YAAY,qBAAqB;AAAA,EAC1C;AAAA,EAEA,MAAM,gBAAgB,OAA8B;AAClD,WAAO,YAAY,uBAAuB,KAAK;AAAA,EACjD;AAAA,EAEA,MAAM,WAAmC;AACvC,UAAM,gBAAgB,MAAM,YAAY,cAAc;AACtD,WAAO,iBAAiB,QAAQ,IAAI,oBAAoB;AAAA,EAC1D;AAAA,EAEA,MAAM,SAAS,OAA8B;AAC3C,WAAO,YAAY,gBAAgB,KAAK;AAAA,EAC1C;AAAA,EAEA,MAAM,eAAuC;AAC3C,UAAM,gBAAgB,MAAM,YAAY,kBAAkB;AAC1D,WAAO,iBAAiB,QAAQ,IAAI,wBAAwB;AAAA,EAC9D;AAAA,EAEA,MAAM,aAAa,WAAkC;AACnD,WAAO,YAAY,oBAAoB,SAAS;AAAA,EAClD;AAAA,EAEA,MAAM,kBAAoC;AACxC,WAAQ,MAAM,KAAK,eAAe,MAAO;AAAA,EAC3C;AAAA,EAEA,MAAM,SAAwB;AAC5B,UAAM,eAAe,oBAAoB;AACzC,UAAM,eAAe,qBAAqB;AAC1C,WAAO,oBAAoB;AAAA,EAC7B;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,eAAe,oBAAoB;AACzC,UAAM,eAAe,qBAAqB;AAC1C,UAAM,eAAe,cAAc;AACnC,UAAM,eAAe,kBAAkB;AACvC,WAAO,MAAM;AAAA,EACf;AACF;AAEO,IAAM,OAAO,IAAI,YAAY;;;AE9G7B,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACE,SACO,YACP;AACA,UAAM,OAAO;AAFN;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACE,SACO,UACA,YACP;AACA,UAAM,OAAO;AAHN;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,qBAA6C;AAAA,EACjD,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,qBAAqB;AACvB;AAEO,SAAS,qBAAqB,SAAyB;AAC5D,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY;AAChB,aAAW,WAAW,mBAAmB;AACvC,gBAAY,UAAU,QAAQ,SAAS,YAAY;AAAA,EACrD;AAEA,SAAO,UAAU,SAAS,MAAM,UAAU,UAAU,GAAG,GAAG,IAAI,QAAQ;AACxE;AAeA,SAAS,cAAc,OAAkD;AACvE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAAS,iBAAiB,OAAgC;AAC/D,MAAI,CAAC,cAAc,KAAK,GAAG;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,WAAW;AAEjB,MAAI,SAAS;AACb,MAAI,SAAS,mBAAmB;AAC9B,aAAS,SAAS;AAAA,EACpB,WAAW,SAAS,SAAS;AAC3B,aAAS,SAAS;AAAA,EACpB,WAAW,SAAS,WAAW,QAAQ,QAAQ;AAC7C,aAAS,SAAS,UAAU,OACzB,IAAI,OAAK,EAAE,WAAW,EAAE,IAAI,EAC5B,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACd;AAEA,SAAO;AAAA,IACL,MAAM,SAAS,SAAS;AAAA,IACxB,QAAQ,qBAAqB,MAAM;AAAA,EACrC;AACF;AAEA,SAAS,oBAAoB,MAAc,QAAgB,YAA2B;AACpF,QAAM,OAAO,SAAS,sBAClB,wEACA;AAEJ,QAAM,WAA2F;AAAA,IAC/F,OAAO,EAAE,MAAM,QAAQ,WAAW;AAAA,EACpC;AAEA,MAAI,MAAM;AACR,aAAS,OAAO;AAAA,EAClB;AAEA,aAAW,QAAQ;AACnB,UAAQ,KAAK,CAAC;AAChB;AAEO,SAAS,qBAAqB,OAAuB;AAC1D,MAAI,iBAAiB,mBAAmB;AACtC,UAAM,YAAY,qBAAqB,MAAM,OAAO;AACpD,wBAAoB,aAAa,WAAW,MAAM,cAAc,CAAC;AAAA,EACnE;AAEA,MAAI,iBAAiB,mBAAmB;AACtC,UAAM,UAA0B,iBAAiB,MAAM,QAAQ;AAC/D;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,QAAQ,IAAI,KAAK;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI,iBAAiB,OAAO;AAC1B,UAAM,YAAY,qBAAqB,MAAM,OAAO;AACpD,wBAAoB,iBAAiB,WAAW,CAAC;AAAA,EACnD;AAEA,sBAAoB,iBAAiB,gCAAgC,CAAC;AACxE;;;ACpIA,OAAO,YAAY;AAWnB,OAAO,OAAO;AAEd,IAAM,WAAW;AACjB,IAAM,YAAY;AAcX,IAAM,kBAAN,MAAsB;AAAA,EACnB,cAA6B;AAAA,EAErC,aAAmB;AACjB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAM,qBAAsC;AAC1C,UAAM,QAAQ,MAAM,KAAK,SAAS;AAClC,UAAM,YAAY,MAAM,KAAK,aAAa;AAC1C,UAAM,eAAe,MAAM,KAAK,gBAAgB;AAEhD,QAAI,CAAC,SAAS,CAAC,WAAW;AACxB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,cAAc;AAChB,UAAI;AACF,cAAMC,YAAW,MAAM,MAAM,WAAW;AAAA,UACtC,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,UAC/D,MAAM,IAAI,gBAAgB;AAAA,YACxB,YAAY;AAAA,YACZ,WAAW;AAAA,YACX,eAAe;AAAA,YACf,eAAe;AAAA,UACjB,CAAC;AAAA,QACH,CAAC;AAED,YAAIA,UAAS,IAAI;AACf,gBAAMC,QAAQ,MAAMD,UAAS,KAAK;AAClC,gBAAM,KAAK,eAAeC,MAAK,YAAY;AAC3C,cAAIA,MAAK,eAAe;AACtB,kBAAM,KAAK,gBAAgBA,MAAK,aAAa;AAAA,UAC/C;AACA,eAAK,cAAcA,MAAK;AACxB,iBAAOA,MAAK;AAAA,QACd;AAAA,MACF,SAAS,OAAO;AACd,cAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,gBAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,kDAAkD,QAAQ,QAAQ,CAAC,CAAC;AAAA,MAC9G;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,WAAW;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,QAC/D,MAAM,IAAI,gBAAgB;AAAA,UACxB,YAAY;AAAA,UACZ,WAAW;AAAA,UACX,eAAe;AAAA,QACjB,CAAC;AAAA,MACH,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,YAAM,IAAI,kBAAkB,iDAAiD,OAAO,IAAI,CAAC;AAAA,IAC3F;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,kBAAkB,8BAA8B,OAAO,SAAS,MAAM;AAAA,IAClF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,UAAM,KAAK,eAAe,KAAK,YAAY;AAC3C,SAAK,cAAc,KAAK;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,iBAAkC;AACtC,QAAI,KAAK,aAAa;AACpB,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,cAAc,MAAM,KAAK,eAAe;AAC9C,QAAI,aAAa;AACf,WAAK,cAAc;AACnB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,mBAAmB;AAAA,EACjC;AAAA,EAEA,MAAc,QACZ,QACA,MACA,UAKI,CAAC,GACO;AACZ,UAAM,EAAE,QAAQ,MAAM,QAAQ,MAAM,iBAAiB,KAAK,IAAI;AAE9D,UAAM,MAAM,IAAI,IAAI,GAAG,QAAQ,GAAG,IAAI,EAAE;AACxC,QAAI,QAAQ;AACV,aAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAC/C,YAAI,UAAU,QAAW;AACvB,cAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,QAAQ,MAAM,KAAK,eAAe;AACxC,UAAM,eAA4B;AAAA,MAChC;AAAA,MACA,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,IACF;AACA,QAAI,MAAM;AACR,mBAAa,OAAO,KAAK,UAAU,IAAI;AAAA,IACzC;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,IAAI,SAAS,GAAG,YAAY;AAAA,IACrD,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,YAAM,IAAI,kBAAkB,2BAA2B,OAAO,IAAI,CAAC;AAAA,IACrE;AAEA,QAAI,SAAS,WAAW,OAAO,OAAO;AACpC,WAAK,cAAc;AACnB,YAAM,KAAK,mBAAmB;AAC9B,aAAO,KAAK,QAAQ,QAAQ,MAAM,EAAE,GAAG,SAAS,OAAO,MAAM,CAAC;AAAA,IAChE;AAEA,QAAI,SAAS,WAAW,OAAO,gBAAgB;AAC7C,YAAM,aAAa,SAAS,SAAS,QAAQ,IAAI,aAAa,KAAK,MAAM,EAAE;AAC3E,YAAM,cAAc,KAAK,IAAI,YAAY,GAAG;AAC5C,cAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,yBAAyB,WAAW,oBAAoB,CAAC,CAAC;AAClG,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,cAAc,GAAI,CAAC;AACtE,aAAO,KAAK,QAAQ,QAAQ,MAAM,EAAE,GAAG,SAAS,gBAAgB,MAAM,CAAC;AAAA,IACzE;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACpD,YAAM,IAAI,kBAAkB,sBAAsB,OAAO,SAAS,MAAM;AAAA,IAC1E;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA,EAIA,MAAM,kBAAkB,SAWpB,CAAC,GAAG;AACN,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AACA,WAAO;AAAA,MACL,eAAe,SAAS,WAAW,iBAAiB,CAAC;AAAA,MACrD,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,qBAAqB,SAOvB,CAAC,GAA4B;AAC/B,UAAM,mBAAmC,CAAC;AAC1C,QAAI,OAAO;AACX,QAAI,aAAa;AAEjB,OAAG;AACD,YAAM,SAAS,MAAM,KAAK,kBAAkB,EAAE,GAAG,QAAQ,KAAK,CAAC;AAC/D,uBAAiB,KAAK,GAAG,OAAO,aAAa;AAC7C,mBAAa,OAAO,KAAK;AACzB;AAAA,IACF,SAAS,QAAQ;AAEjB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,gBAAwB,OAAgB;AAC5D,UAAM,SAAS,QAAQ,EAAE,MAAM,IAAI;AACnC,WAAO,KAAK,QAAsB,OAAO,kBAAkB,cAAc,IAAI,EAAE,OAAO,CAAC;AAAA,EACzF;AAAA,EAEA,MAAM,uBAAuB,gBAAwB;AACnD,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA,kBAAkB,cAAc;AAAA,IAClC;AACA,WAAO,SAAS,WAAW,WAAW,CAAC;AAAA,EACzC;AAAA,EAEA,MAAM,mBACJ,gBACA,MAKA;AACA,UAAM,KAAK,QAAc,SAAS,kBAAkB,cAAc,IAAI,EAAE,MAAM,KAAK,CAAC;AAAA,EACtF;AAAA,EAEA,MAAM,mBAAmB,gBAAwB;AAC/C,UAAM,KAAK,QAAc,UAAU,kBAAkB,cAAc,EAAE;AAAA,EACvE;AAAA,EAEA,MAAM,mBAAmB,gBAAwB,KAAa;AAC5D,UAAM,KAAK,QAAc,OAAO,kBAAkB,cAAc,SAAS;AAAA,MACvE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,sBAAsB,gBAAwB,KAAa;AAC/D,UAAM,eAAe,MAAM,KAAK,gBAAgB,cAAc;AAC9D,UAAM,eAAe,cAAc,MAAM,IAAI,OAAK,EAAE,IAAI,KAAK,CAAC;AAC9D,UAAM,UAAU,aAAa,OAAO,OAAK,MAAM,GAAG;AAClD,UAAM,KAAK,QAAc,OAAO,kBAAkB,cAAc,SAAS;AAAA,MACvE,MAAM,EAAE,MAAM,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YACJ,gBACA,MAMA;AACA,UAAM,KAAK,QAAc,QAAQ,kBAAkB,cAAc,UAAU,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3F;AAAA,EAEA,MAAM,WACJ,gBACA,MAIA;AACA,UAAM,KAAK,QAAc,QAAQ,kBAAkB,cAAc,UAAU,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3F;AAAA;AAAA,EAGA,MAAM,cAAc,SAShB,CAAC,GAAG;AACN,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AACA,WAAO;AAAA,MACL,WAAW,SAAS,WAAW,aAAa,CAAC;AAAA,MAC7C,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,YAAoB;AACpC,WAAO,KAAK,QAAkB,OAAO,cAAc,UAAU,EAAE;AAAA,EACjE;AAAA,EAEA,MAAM,eAAe,MAKlB;AACD,UAAM,KAAK,QAAc,QAAQ,cAAc,EAAE,MAAM,KAAK,CAAC;AAAA,EAC/D;AAAA,EAEA,MAAM,eACJ,YACA,MAQA;AACA,UAAM,KAAK,QAAc,OAAO,cAAc,UAAU,IAAI,EAAE,MAAM,KAAK,CAAC;AAAA,EAC5E;AAAA,EAEA,MAAM,eAAe,YAAoB;AACvC,UAAM,KAAK,QAAc,UAAU,cAAc,UAAU,EAAE;AAAA,EAC/D;AAAA;AAAA,EAGA,MAAM,SAAS,MAAe;AAC5B,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,OAAO,EAAE,KAAK,IAAI,OAAU;AAAA,IACxC;AACA,WAAO;AAAA,MACL,MAAM,SAAS,WAAW,QAAQ,CAAC;AAAA,MACnC,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,OAAe;AAC1B,WAAO,KAAK,QAAa,OAAO,SAAS,KAAK,EAAE;AAAA,EAClD;AAAA;AAAA,EAGA,MAAM,cAAc,SAIhB,CAAC,GAAG;AACN,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,EAAE,WAAW,OAAO,SAAS,MAAM,OAAO,MAAM,MAAM,OAAO,KAAK,EAAE;AAAA,IAChF;AACA,WAAO;AAAA,MACL,WAAW,SAAS,WAAW,aAAa,CAAC;AAAA,MAC7C,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,YAAoB,iBAA2B;AAC/D,UAAM,KAAK,QAAc,QAAQ,cAAc,UAAU,QAAQ;AAAA,MAC/D,MAAM,EAAE,gBAAgB;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,qBAAqB,YAAoB,QAA+B;AAC5E,UAAM,KAAK,QAAc,SAAS,cAAc,UAAU,IAAI;AAAA,MAC5D,MAAM,EAAE,IAAI,WAAW,MAAM,WAAW,OAAO,OAAO;AAAA,IACxD,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,cAAc,MAAe;AACjC,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,OAAO,EAAE,KAAK,IAAI,OAAU;AAAA,IACxC;AACA,WAAO;AAAA,MACL,WAAW,SAAS,WAAW,aAAa,CAAC;AAAA,MAC7C,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,WAAmB;AAClC,WAAO,KAAK,QAAiB,OAAO,cAAc,SAAS,EAAE;AAAA,EAC/D;AACF;AAEO,IAAM,SAAS,IAAI,gBAAgB;;;AC3ZnC,SAAS,kBACd,IAC+B;AAC/B,SAAO,UAAU,SAAY;AAC3B,QAAI;AACF,YAAM,GAAG,GAAG,IAAI;AAAA,IAClB,SAAS,OAAO;AACd,2BAAqB,KAAK;AAAA,IAC5B;AAAA,EACF;AACF;AAEO,SAAS,WAAW,OAAe,eAAuB,YAAoB;AACnF,QAAM,SAAS,SAAS,OAAO,EAAE;AACjC,MAAI,MAAM,MAAM,KAAK,UAAU,GAAG;AAChC,UAAM,IAAI,kBAAkB,WAAW,YAAY,SAAS,KAAK,KAAK,GAAG;AAAA,EAC3E;AACA,SAAO;AACT;AAEO,SAAS,uBACd,MACA,WACM;AACN,QAAM,YAAY,OAAO,OAAO,IAAI,EAAE,KAAK,CAAC,MAAM,MAAM,MAAS;AACjE,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,kBAAkB,GAAG,SAAS,0CAA0C,GAAG;AAAA,EACvF;AACF;AAEA,eAAsB,cACpB,cACA,kBACkB;AAClB,MAAI,kBAAkB;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,OAAO,UAAU;AACxC,QAAM,KAAK,SAAS,gBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,UAAU,YAAY,YAAY,CAAC,WAAW;AACxD,SAAG,MAAM;AACT,UAAI,OAAO,YAAY,MAAM,KAAK;AAChC,mBAAW,EAAE,WAAW,MAAM,SAAS,qBAAqB,CAAC;AAC7D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;;;ALnDO,SAAS,oBAA6B;AAC3C,QAAM,MAAM,IAAI,QAAQ,MAAM,EAAE,YAAY,2BAA2B;AAEvE,MACG,QAAQ,OAAO,EACf,YAAY,sCAAsC,EAClD,eAAe,iBAAiB,mBAAmB,EACnD,eAAe,yBAAyB,uBAAuB,EAC/D,OAAO,kBAAkB,OAAO,YAAkD;AACjF,UAAM,KAAK,SAAS,QAAQ,KAAK;AACjC,UAAM,KAAK,aAAa,QAAQ,SAAS;AAEzC,WAAO,WAAW;AAClB,UAAM,OAAO,mBAAmB;AAEhC,eAAW,EAAE,SAAS,6CAA6C,CAAC;AAAA,EACtE,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,2BAA2B,EACvC,OAAO,kBAAkB,YAAY;AACpC,UAAM,KAAK,OAAO;AAClB,WAAO,WAAW;AAClB,eAAW,EAAE,SAAS,0BAA0B,CAAC;AAAA,EACnD,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,6BAA6B,EACzC,OAAO,kBAAkB,YAAY;AACpC,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,UAAM,WAAW,CAAC,CAAE,MAAM,KAAK,SAAS;AACxC,UAAM,eAAe,CAAC,CAAE,MAAM,KAAK,aAAa;AAEhD,eAAW;AAAA,MACT,eAAe;AAAA,MACf,YAAY,YAAY;AAAA,IAC1B,CAAC;AAAA,EACH,CAAC,CAAC;AAEJ,MACG,QAAQ,SAAS,EACjB,YAAY,sBAAsB,EAClC,OAAO,kBAAkB,YAAY;AACpC,WAAO,WAAW;AAClB,UAAM,OAAO,mBAAmB;AAChC,eAAW,EAAE,SAAS,yBAAyB,CAAC;AAAA,EAClD,CAAC,CAAC;AAEJ,SAAO;AACT;;;AMzDA,SAAS,WAAAC,gBAAe;AAMjB,SAAS,yBAAkC;AAChD,QAAM,MAAM,IAAIC,SAAQ,WAAW,EAAE,YAAY,oBAAoB;AAErE,MACG,QAAQ,MAAM,EACd,YAAY,gBAAgB,EAC5B,OAAO,mBAAmB,aAAa,EACvC,OAAO,kBAAkB,OAAO,YAA+B;AAC9D,UAAM,SAAS,MAAM,OAAO,cAAc,QAAQ,OAAO,SAAS,QAAQ,MAAM,EAAE,IAAI,MAAS;AAC/F,eAAW,MAAM;AAAA,EACnB,CAAC,CAAC;AAEJ,MACG,QAAQ,MAAM,EACd,YAAY,gBAAgB,EAC5B,SAAS,QAAQ,YAAY,EAC7B,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,UAAU,MAAM,OAAO,WAAW,WAAW,IAAI,SAAS,CAAC;AACjE,eAAW,OAAO;AAAA,EACpB,CAAC,CAAC;AAEJ,MACG,QAAQ,aAAa,EACrB,YAAY,qBAAqB,EACjC,SAAS,QAAQ,YAAY,EAC7B,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,YAAY,WAAW,IAAI,SAAS;AAC1C,WAAO,kBAAkB,OAAO,SAAS,CAAC;AAC1C,eAAW,EAAE,SAAS,0BAA0B,SAAS,GAAG,CAAC;AAAA,EAC/D,CAAC,CAAC;AAEJ,MACG,QAAQ,aAAa,EACrB,YAAY,qBAAqB,EACjC,OAAO,kBAAkB,YAAY;AACpC,UAAM,YAAY,OAAO,kBAAkB;AAC3C,eAAW,EAAE,gBAAgB,aAAa,KAAK,CAAC;AAAA,EAClD,CAAC,CAAC;AAEJ,MACG,QAAQ,eAAe,EACvB,YAAY,uBAAuB,EACnC,OAAO,kBAAkB,YAAY;AACpC,WAAO,oBAAoB;AAC3B,eAAW,EAAE,SAAS,0BAA0B,CAAC;AAAA,EACnD,CAAC,CAAC;AAEJ,SAAO;AACT;;;ACtDA,SAAS,WAAAC,gBAAe;AAmBxB,SAAS,uBAAuB,eAAoD;AAClF,QAAM,WAAmC,CAAC;AAC1C,QAAM,QAAgC,CAAC;AAEvC,aAAW,QAAQ,eAAe;AAChC,aAAS,KAAK,MAAM,KAAK,SAAS,KAAK,MAAM,KAAK,KAAK;AAEvD,eAAW,OAAO,KAAK,QAAQ,CAAC,GAAG;AACjC,YAAM,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,cAAc;AAAA,IACrB;AAAA,IACA;AAAA,IACA,eAAe,cAAc,IAAI,QAAM;AAAA,MACrC,IAAI,EAAE;AAAA,MACN,SAAS,EAAE;AAAA,MACX,QAAQ,EAAE;AAAA,MACV,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,OAAK,EAAE,IAAI;AAAA,MACpC,SAAS,EAAE;AAAA,IACb,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,6BAAsC;AACpD,QAAM,MAAM,IAAIC,SAAQ,eAAe,EAAE,YAAY,yBAAyB;AAE9E,MACG,QAAQ,MAAM,EACd,YAAY,oBAAoB,EAChC,OAAO,sBAAsB,sBAAsB,EACnD,OAAO,yBAAyB,6DAA6D,EAC7F,OAAO,oBAAoB,mCAAmC,EAC9D,OAAO,sBAAsB,4BAA4B,EACzD,OAAO,2BAA2B,oCAAoC,EACtE,OAAO,wBAAwB,gEAAgE,EAC/F,OAAO,wBAAwB,wBAAwB,EACvD,OAAO,mBAAmB,aAAa,EACvC,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,uBAAuB,iGAAiG,EAC/H,OAAO,aAAa,6DAA6D,EACjF,OAAO,kBAAkB,OAAO,YAY3B;AACJ,QAAI,QAAQ,SAAS;AACnB,YAAM,mBAAmB,MAAM,OAAO,qBAAqB;AAAA,QACzD,SAAS,QAAQ;AAAA,QACjB,QAAQ,QAAQ;AAAA,QAChB,KAAK,QAAQ;AAAA,QACb,YAAY,QAAQ;AAAA,QACpB,eAAe,QAAQ;AAAA,QACvB,OAAO,QAAQ;AAAA,MACjB,CAAC;AACD,YAAM,UAAU,uBAAuB,gBAAgB;AACvD,iBAAW,OAAO;AAClB;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,OAAO,kBAAkB;AAAA,MAC5C,SAAS,QAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,KAAK,QAAQ;AAAA,MACb,YAAY,QAAQ;AAAA,MACpB,eAAe,QAAQ;AAAA,MACvB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,MAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,EAAE,IAAI;AAAA,MAClD,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,IACjB,CAAC;AACD,eAAW,MAAM;AAAA,EACnB,CAAC,CAAC;AAEJ,MACG,QAAQ,MAAM,EACd,YAAY,qBAAqB,EACjC,SAAS,QAAQ,iBAAiB,EAClC,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,kBAAkB,OAAO,IAAY,YAAgC;AAC3E,UAAM,eAAe,MAAM,OAAO,gBAAgB,WAAW,IAAI,cAAc,GAAG,QAAQ,KAAK;AAC/F,eAAW,YAAY;AAAA,EACzB,CAAC,CAAC;AAEJ,MACG,QAAQ,SAAS,EACjB,YAAY,yEAAyE,EACrF,SAAS,QAAQ,iBAAiB,EAClC,OAAO,mBAAmB,wBAAwB,EAClD,OAAO,SAAS,4DAA4D,EAC5E,OAAO,sBAAsB,8IAA8I,EAC3K,OAAO,kBAAkB,OAAO,IAAY,YAAsE;AACjH,QAAI,UAAU,MAAM,OAAO,uBAAuB,WAAW,IAAI,cAAc,CAAC;AAEhF,QAAI,QAAQ,MAAM;AAChB,YAAM,QAAQ,QAAQ,KAAK,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,EAAE,YAAY,CAAC;AACrE,gBAAU,QAAQ,OAAO,OAAK,MAAM,SAAS,EAAE,IAAI,CAAC;AAAA,IACtD,WAAW,CAAC,QAAQ,KAAK;AACvB,YAAM,eAAe,QAAQ,eACzB,CAAC,YAAY,WAAW,QAAQ,QAAQ,OAAO,IAC/C,CAAC,YAAY,WAAW,QAAQ,OAAO;AAC3C,gBAAU,QAAQ,OAAO,OAAK,aAAa,SAAS,EAAE,IAAI,CAAC;AAAA,IAC7D;AAEA,eAAW,OAAO;AAAA,EACpB,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,uBAAuB,EACnC,SAAS,QAAQ,iBAAiB,EAClC,OAAO,aAAa,mBAAmB,EACvC,OAAO,kBAAkB,OAAO,IAAY,YAA+B;AAC1E,UAAM,cAAc,gBAAgB,QAAQ,GAAG;AAC/C,UAAM,OAAO,mBAAmB,WAAW,IAAI,cAAc,CAAC;AAC9D,eAAW,EAAE,SAAS,uBAAuB,CAAC;AAAA,EAChD,CAAC,CAAC;AAEJ,MACG,QAAQ,SAAS,EACjB,YAAY,6BAA6B,EACzC,SAAS,QAAQ,iBAAiB,EAClC,SAAS,SAAS,UAAU,EAC5B,OAAO,kBAAkB,OAAO,IAAY,QAAgB;AAC3D,UAAM,OAAO,mBAAmB,WAAW,IAAI,cAAc,GAAG,GAAG;AACnE,eAAW,EAAE,SAAS,QAAQ,GAAG,UAAU,CAAC;AAAA,EAC9C,CAAC,CAAC;AAEJ,MACG,QAAQ,YAAY,EACpB,YAAY,kCAAkC,EAC9C,SAAS,QAAQ,iBAAiB,EAClC,SAAS,SAAS,UAAU,EAC5B,OAAO,kBAAkB,OAAO,IAAY,QAAgB;AAC3D,UAAM,OAAO,sBAAsB,WAAW,IAAI,cAAc,GAAG,GAAG;AACtE,eAAW,EAAE,SAAS,QAAQ,GAAG,YAAY,CAAC;AAAA,EAChD,CAAC,CAAC;AAEJ,MACG,QAAQ,OAAO,EACf,YAAY,yBAAyB,EACrC,SAAS,QAAQ,iBAAiB,EAClC,eAAe,iBAAiB,YAAY,EAC5C,OAAO,eAAe,2BAA2B,EACjD,OAAO,WAAW,eAAe,EACjC,OAAO,qBAAqB,+DAA+D,EAC3F,OAAO,kBAAkB,OAAO,IAAY,YAKvC;AACJ,UAAM,OAAO,YAAY,WAAW,IAAI,cAAc,GAAG;AAAA,MACvD,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ,OAAO,WAAW,QAAQ,MAAM,MAAM,IAAI;AAAA,MACxD,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,eAAW,EAAE,SAAS,aAAa,CAAC;AAAA,EACtC,CAAC,CAAC;AAEJ,MACG,QAAQ,MAAM,EACd,YAAY,8BAA8B,EAC1C,SAAS,QAAQ,iBAAiB,EAClC,eAAe,iBAAiB,WAAW,EAC3C,OAAO,eAAe,yBAAyB,EAC/C,OAAO,kBAAkB,OAAO,IAAY,YAGvC;AACJ,UAAM,OAAO,WAAW,WAAW,IAAI,cAAc,GAAG;AAAA,MACtD,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ,OAAO,WAAW,QAAQ,MAAM,MAAM,IAAI;AAAA,IAC1D,CAAC;AACD,eAAW,EAAE,SAAS,aAAa,CAAC;AAAA,EACtC,CAAC,CAAC;AAEJ,SAAO;AACT;;;ACjNA,SAAS,WAAAC,gBAAe;AAKjB,SAAS,yBAAkC;AAChD,QAAM,MAAM,IAAIC,SAAQ,WAAW,EAAE,YAAY,qBAAqB;AAEtE,MACG,QAAQ,MAAM,EACd,YAAY,gBAAgB,EAC5B,OAAO,sBAAsB,sBAAsB,EACnD,OAAO,uBAAuB,sBAAsB,EACpD,OAAO,sBAAsB,qBAAqB,EAClD,OAAO,2BAA2B,oCAAoC,EACtE,OAAO,wBAAwB,4DAA4D,EAC3F,OAAO,wBAAwB,wBAAwB,EACvD,OAAO,mBAAmB,aAAa,EACvC,OAAO,uBAAuB,uBAAuB,EACrD,OAAO,kBAAkB,OAAO,YAS3B;AACJ,UAAM,SAAS,MAAM,OAAO,cAAc;AAAA,MACxC,SAAS,QAAQ;AAAA,MACjB,WAAW,QAAQ;AAAA,MACnB,UAAU,QAAQ;AAAA,MAClB,eAAe,QAAQ;AAAA,MACvB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,MAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,EAAE,IAAI;AAAA,MAClD,OAAO,QAAQ;AAAA,IACjB,CAAC;AACD,eAAW,MAAM;AAAA,EACnB,CAAC,CAAC;AAEJ,MACG,QAAQ,MAAM,EACd,YAAY,iBAAiB,EAC7B,SAAS,QAAQ,aAAa,EAC9B,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,WAAW,MAAM,OAAO,YAAY,WAAW,IAAI,UAAU,CAAC;AACpE,eAAW,QAAQ;AAAA,EACrB,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,OAAO,uBAAuB,YAAY,EAC1C,OAAO,sBAAsB,WAAW,EACxC,OAAO,mBAAmB,eAAe,EACzC,OAAO,mBAAmB,cAAc,EACxC,OAAO,kBAAkB,OAAO,YAK3B;AACJ,UAAM,OAAO;AAAA,MACX,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,QAAQ,OAAO,QAAQ,MAAM,CAAC,EAAE;AAAA,MACxE,GAAI,QAAQ,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,QAAQ,OAAO,QAAQ,MAAM,CAAC,EAAE;AAAA,IAC1E;AACA,2BAAuB,MAAM,iBAAiB;AAC9C,UAAM,OAAO,eAAe,IAAI;AAChC,eAAW,EAAE,SAAS,mBAAmB,CAAC;AAAA,EAC5C,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,SAAS,QAAQ,aAAa,EAC9B,OAAO,uBAAuB,YAAY,EAC1C,OAAO,sBAAsB,WAAW,EACxC,OAAO,uBAAuB,WAAW,EACzC,OAAO,yBAAyB,UAAU,EAC1C,OAAO,wBAAwB,cAAc,EAC7C,OAAO,uBAAuB,kBAAkB,EAChD,OAAO,kBAAkB,OAAO,IAAY,YAOvC;AACJ,UAAM,OAAO;AAAA,MACX,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,gBAAgB,EAAE,cAAc,QAAQ,aAAa;AAAA,MACjE,GAAI,QAAQ,cAAc,EAAE,YAAY,QAAQ,WAAW;AAAA,IAC7D;AACA,2BAAuB,MAAM,iBAAiB;AAC9C,UAAM,OAAO,eAAe,WAAW,IAAI,UAAU,GAAG,IAAI;AAC5D,eAAW,EAAE,SAAS,mBAAmB,CAAC;AAAA,EAC5C,CAAC,CAAC;AAEJ,MACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,SAAS,QAAQ,aAAa,EAC9B,OAAO,aAAa,mBAAmB,EACvC,OAAO,kBAAkB,OAAO,IAAY,YAA+B;AAC1E,UAAM,cAAc,YAAY,QAAQ,GAAG;AAC3C,UAAM,OAAO,eAAe,WAAW,IAAI,UAAU,CAAC;AACtD,eAAW,EAAE,SAAS,mBAAmB,CAAC;AAAA,EAC5C,CAAC,CAAC;AAEJ,SAAO;AACT;;;ACtHA,SAAS,WAAAC,gBAAe;AAKjB,SAAS,oBAA6B;AAC3C,QAAM,MAAM,IAAIC,SAAQ,MAAM,EAAE,YAAY,gBAAgB;AAE5D,MACG,QAAQ,MAAM,EACd,YAAY,eAAe,EAC3B,OAAO,mBAAmB,aAAa,EACvC,OAAO,kBAAkB,OAAO,YAA+B;AAC9D,UAAM,SAAS,MAAM,OAAO,SAAS,QAAQ,OAAO,SAAS,QAAQ,MAAM,EAAE,IAAI,MAAS;AAC1F,eAAW,MAAM;AAAA,EACnB,CAAC,CAAC;AAEJ,MACG,QAAQ,MAAM,EACd,YAAY,YAAY,EACxB,SAAS,QAAQ,QAAQ,EACzB,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,MAAM,MAAM,OAAO,OAAO,WAAW,IAAI,KAAK,CAAC;AACrD,eAAW,GAAG;AAAA,EAChB,CAAC,CAAC;AAEJ,SAAO;AACT;;;AC3BA,SAAS,WAAAC,gBAAe;AAKjB,SAAS,yBAAkC;AAChD,QAAM,MAAM,IAAIC,SAAQ,WAAW,EAAE,YAAY,qBAAqB;AAEtE,MACG,QAAQ,MAAM,EACd,YAAY,gBAAgB,EAC5B,OAAO,sBAAsB,sBAAsB,EACnD,OAAO,qBAAqB,oCAAoC,EAChE,OAAO,mBAAmB,aAAa,EACvC,OAAO,kBAAkB,OAAO,YAI3B;AACJ,UAAM,SAAS,MAAM,OAAO,cAAc;AAAA,MACxC,SAAS,QAAQ,UAAU,WAAW,QAAQ,SAAS,SAAS,IAAI;AAAA,MACpE,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,EAAE,IAAI;AAAA,IACpD,CAAC;AACD,eAAW,MAAM;AAAA,EACnB,CAAC,CAAC;AAEJ,MACG,QAAQ,KAAK,EACb,YAAY,wCAAwC,EACpD,SAAS,iBAAiB,aAAa,EACvC,eAAe,yBAAyB,kCAAkC,EAC1E,OAAO,kBAAkB,OAAO,YAAoB,YAAuC;AAC1F,UAAM,kBAAkB,QAAQ,cAAc,MAAM,GAAG,EAAE,IAAI,QAAM,WAAW,GAAG,KAAK,GAAG,cAAc,CAAC;AACxG,UAAM,OAAO,YAAY,WAAW,YAAY,UAAU,GAAG,eAAe;AAC5E,eAAW,EAAE,SAAS,oBAAoB,CAAC;AAAA,EAC7C,CAAC,CAAC;AAEJ,MACG,QAAQ,UAAU,EAClB,YAAY,qBAAqB,EACjC,SAAS,QAAQ,aAAa,EAC9B,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,OAAO,qBAAqB,WAAW,IAAI,UAAU,GAAG,QAAQ;AACtE,eAAW,EAAE,SAAS,qBAAqB,CAAC;AAAA,EAC9C,CAAC,CAAC;AAEJ,MACG,QAAQ,YAAY,EACpB,YAAY,uBAAuB,EACnC,SAAS,QAAQ,aAAa,EAC9B,OAAO,kBAAkB,OAAO,OAAe;AAC9C,UAAM,OAAO,qBAAqB,WAAW,IAAI,UAAU,GAAG,UAAU;AACxE,eAAW,EAAE,SAAS,uBAAuB,CAAC;AAAA,EAChD,CAAC,CAAC;AAEJ,SAAO;AACT;;;AZ5CA,IAAM,UAAU,IAAIC,SAAQ;AAE5B,QACG,KAAK,WAAW,EAChB,YAAY,yCAAyC,EACrD,QAAQ,OAAW,EACnB,OAAO,iBAAiB,oCAAoC,EAC5D,OAAO,eAAe,gDAAgD,EACtE,OAAO,sBAAsB,iEAAiE,EAC9F,OAAO,yBAAyB,qDAAqD,EACrF,KAAK,aAAa,CAAC,gBAAgB;AAClC,QAAM,UAAU,YAAY,KAAK;AACjC,mBAAiB;AAAA,IACf,SAAS,QAAQ;AAAA,IACjB,MAAM,CAAC,QAAQ;AAAA,IACf,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH,CAAC;AAEH,QAAQ,WAAW,kBAAkB,CAAC;AACtC,QAAQ,WAAW,uBAAuB,CAAC;AAC3C,QAAQ,WAAW,2BAA2B,CAAC;AAC/C,QAAQ,WAAW,uBAAuB,CAAC;AAC3C,QAAQ,WAAW,kBAAkB,CAAC;AACtC,QAAQ,WAAW,uBAAuB,CAAC;AAE3C,QAAQ,WAAW,EAAE,MAAM,MAAM;AAC/B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["Command","result","response","data","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/lib/errors.ts","../src/lib/api-client.ts","../src/lib/command-utils.ts","../src/commands/mailboxes.ts","../src/commands/conversations.ts","../src/commands/customers.ts","../src/commands/tags.ts","../src/commands/workflows.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createMailboxesCommand } from './commands/mailboxes.js';\nimport { createConversationsCommand } from './commands/conversations.js';\nimport { createCustomersCommand } from './commands/customers.js';\nimport { createTagsCommand } from './commands/tags.js';\nimport { createWorkflowsCommand } from './commands/workflows.js';\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name('helpscout')\n .description('A command-line interface for Help Scout')\n .version(__VERSION__)\n .option('-c, --compact', 'Minified JSON output (single line)')\n .option('-p, --plain', 'Strip HTML from body fields, output plain text')\n .option('--include-metadata', 'Include _links and _embedded in responses (stripped by default)')\n .option('-f, --fields <fields>', 'Comma-separated list of fields to include in output')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n slim: !options.includeMetadata,\n plain: options.plain,\n fields: options.fields,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createMailboxesCommand());\nprogram.addCommand(createConversationsCommand());\nprogram.addCommand(createCustomersCommand());\nprogram.addCommand(createTagsCommand());\nprogram.addCommand(createWorkflowsCommand());\n\nprogram.parseAsync().catch(() => {\n process.exit(1);\n});\n","import { convert } from 'html-to-text';\nimport type { OutputOptions } from '../types/index.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction htmlToPlainText(html: string): string {\n const text = convert(html, {\n wordwrap: false,\n preserveNewlines: false,\n selectors: [\n { selector: 'a', options: { ignoreHref: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n\n return text\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/[ \\t]+/g, ' ')\n .trim();\n}\n\nfunction convertBodiesToPlainText(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(convertBodiesToPlainText);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key === 'body' && typeof value === 'string') {\n result[key] = htmlToPlainText(value);\n } else {\n result[key] = convertBodiesToPlainText(value);\n }\n }\n return result;\n }\n\n return data;\n}\n\nfunction stripMetadata(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(stripMetadata);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key === '_links' || key === '_embedded') {\n continue;\n }\n result[key] = stripMetadata(value);\n }\n return result;\n }\n\n return data;\n}\n\nfunction stripTagStyles(data: unknown): unknown {\n if (Array.isArray(data)) {\n return data.map(stripTagStyles);\n }\n\n if (isObject(data)) {\n const result: Record<string, unknown> = {};\n const isTag = 'id' in data && 'name' in data && 'slug' in data;\n\n for (const [key, value] of Object.entries(data)) {\n if (isTag && (key === 'color' || key === 'styles')) {\n continue;\n }\n result[key] = stripTagStyles(value);\n }\n return result;\n }\n\n return data;\n}\n\nfunction selectFields(data: unknown, fields: string[]): unknown {\n if (Array.isArray(data)) {\n return data.map((item) => selectFields(item, fields));\n }\n\n if (isObject(data)) {\n const hasRequestedFields = fields.some((f) => f in data);\n if (hasRequestedFields) {\n const result: Record<string, unknown> = {};\n for (const field of fields) {\n if (field in data) {\n result[field] = data[field];\n }\n }\n return result;\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n result[key] = selectFields(value, fields);\n }\n return result;\n }\n\n return data;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const mergedOptions = { ...globalOutputOptions, ...options };\n\n let processed = data;\n\n if (mergedOptions.slim) {\n processed = stripMetadata(processed);\n }\n\n if (mergedOptions.plain) {\n processed = convertBodiesToPlainText(processed);\n }\n\n processed = stripTagStyles(processed);\n\n if (mergedOptions.fields) {\n const fieldList = mergedOptions.fields.split(',').map((f) => f.trim());\n processed = selectFields(processed, fieldList);\n }\n\n const jsonString = mergedOptions.compact\n ? JSON.stringify(processed)\n : JSON.stringify(processed, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication operations');\n\n cmd\n .command('login')\n .description('Configure Help Scout API credentials')\n .requiredOption('--app-id <id>', 'Help Scout App ID')\n .requiredOption('--app-secret <secret>', 'Help Scout App Secret')\n .action(\n withErrorHandling(async (options: { appId: string; appSecret: string }) => {\n await auth.setAppId(options.appId);\n await auth.setAppSecret(options.appSecret);\n\n client.clearToken();\n await client.refreshAccessToken();\n\n outputJson({ message: 'Successfully authenticated with Help Scout' });\n })\n );\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(\n withErrorHandling(async () => {\n await auth.logout();\n client.clearToken();\n outputJson({ message: 'Logged out successfully' });\n })\n );\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(\n withErrorHandling(async () => {\n const hasToken = await auth.isAuthenticated();\n const hasAppId = !!(await auth.getAppId());\n const hasAppSecret = !!(await auth.getAppSecret());\n\n outputJson({\n authenticated: hasToken,\n configured: hasAppId && hasAppSecret,\n });\n })\n );\n\n cmd\n .command('refresh')\n .description('Refresh access token')\n .action(\n withErrorHandling(async () => {\n client.clearToken();\n await client.refreshAccessToken();\n outputJson({ message: 'Access token refreshed' });\n })\n );\n\n return cmd;\n}\n","import { Entry } from '@napi-rs/keyring';\nimport { config } from './config.js';\n\nconst SERVICE_NAME = 'helpscout-cli';\nconst ACCESS_TOKEN_ACCOUNT = 'access-token';\nconst REFRESH_TOKEN_ACCOUNT = 'refresh-token';\nconst APP_ID_ACCOUNT = 'app-id';\nconst APP_SECRET_ACCOUNT = 'app-secret';\n\nconst KEYRING_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: npm install -g @stephendolan/helpscout-cli\\n' +\n 'Alternatively, use HELPSCOUT_APP_ID and HELPSCOUT_APP_SECRET environment variables.';\n\nconst keyringCache = new Map<string, Entry | null>();\n\nfunction getKeyring(account: string): Entry | null {\n if (keyringCache.has(account)) {\n return keyringCache.get(account)!;\n }\n try {\n const entry = new Entry(SERVICE_NAME, account);\n keyringCache.set(account, entry);\n return entry;\n } catch {\n keyringCache.set(account, null);\n return null;\n }\n}\n\nasync function getPassword(account: string): Promise<string | null> {\n const entry = getKeyring(account);\n if (entry) {\n try {\n return entry.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n}\n\nasync function setPassword(account: string, value: string): Promise<void> {\n const entry = getKeyring(account);\n if (!entry) {\n throw new Error(KEYRING_UNAVAILABLE_ERROR);\n }\n entry.setPassword(value);\n}\n\nasync function deletePassword(account: string): Promise<boolean> {\n const entry = getKeyring(account);\n if (entry) {\n return entry.deletePassword();\n }\n return false;\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n return getPassword(ACCESS_TOKEN_ACCOUNT);\n }\n\n async setAccessToken(token: string): Promise<void> {\n return setPassword(ACCESS_TOKEN_ACCOUNT, token);\n }\n\n async getRefreshToken(): Promise<string | null> {\n return getPassword(REFRESH_TOKEN_ACCOUNT);\n }\n\n async setRefreshToken(token: string): Promise<void> {\n return setPassword(REFRESH_TOKEN_ACCOUNT, token);\n }\n\n async getAppId(): Promise<string | null> {\n const keychainValue = await getPassword(APP_ID_ACCOUNT);\n return keychainValue || process.env.HELPSCOUT_APP_ID || null;\n }\n\n async setAppId(appId: string): Promise<void> {\n return setPassword(APP_ID_ACCOUNT, appId);\n }\n\n async getAppSecret(): Promise<string | null> {\n const keychainValue = await getPassword(APP_SECRET_ACCOUNT);\n return keychainValue || process.env.HELPSCOUT_APP_SECRET || null;\n }\n\n async setAppSecret(appSecret: string): Promise<void> {\n return setPassword(APP_SECRET_ACCOUNT, appSecret);\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await deletePassword(ACCESS_TOKEN_ACCOUNT);\n await deletePassword(REFRESH_TOKEN_ACCOUNT);\n config.clearDefaultMailbox();\n }\n\n async clearAll(): Promise<void> {\n await deletePassword(ACCESS_TOKEN_ACCOUNT);\n await deletePassword(REFRESH_TOKEN_ACCOUNT);\n await deletePassword(APP_ID_ACCOUNT);\n await deletePassword(APP_SECRET_ACCOUNT);\n config.clear();\n }\n}\n\nexport const auth = new AuthManager();\n","import Conf from 'conf';\n\ninterface ConfigSchema {\n defaultMailbox?: string;\n}\n\nconst store = new Conf<ConfigSchema>({\n projectName: 'helpscout-cli',\n});\n\nexport const config = {\n getDefaultMailbox(): string | undefined {\n return store.get('defaultMailbox') || process.env.HELPSCOUT_MAILBOX_ID;\n },\n\n setDefaultMailbox(mailboxId: string): void {\n store.set('defaultMailbox', mailboxId);\n },\n\n clearDefaultMailbox(): void {\n store.delete('defaultMailbox');\n },\n\n clear(): void {\n store.clear();\n },\n};\n","import type { HelpScoutError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class HelpScoutCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = 'HelpScoutCliError';\n }\n}\n\nexport class HelpScoutApiError extends Error {\n constructor(\n message: string,\n public apiError: unknown,\n public statusCode: number\n ) {\n super(message);\n this.name = 'HelpScoutApiError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n unauthorized: 401,\n forbidden: 403,\n not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /client[_-]?secret[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface ApiErrorResponse {\n error?: string;\n error_description?: string;\n message?: string;\n _embedded?: {\n errors?: Array<{\n path?: string;\n message?: string;\n rejectedValue?: string;\n }>;\n };\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): HelpScoutError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n };\n }\n\n const apiError = error as ApiErrorResponse;\n\n let detail = 'An error occurred';\n if (apiError.error_description) {\n detail = apiError.error_description;\n } else if (apiError.message) {\n detail = apiError.message;\n } else if (apiError._embedded?.errors?.length) {\n detail = apiError._embedded.errors\n .map((e) => e.message || e.path)\n .filter(Boolean)\n .join('; ');\n }\n\n return {\n name: apiError.error || 'api_error',\n detail: sanitizeErrorMessage(detail),\n };\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const hint =\n name === 'too_many_requests'\n ? 'Help Scout API limit: 200 requests/minute. Wait a moment and retry.'\n : undefined;\n\n const response: { error: { name: string; detail: string; statusCode: number }; hint?: string } = {\n error: { name, detail, statusCode },\n };\n\n if (hint) {\n response.hint = hint;\n }\n\n outputJson(response);\n process.exit(1);\n}\n\nexport function handleHelpScoutError(error: unknown): never {\n if (error instanceof HelpScoutCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n if (error instanceof HelpScoutApiError) {\n const hsError: HelpScoutError = sanitizeApiError(error.apiError);\n formatErrorResponse(\n hsError.name,\n hsError.detail,\n error.statusCode || ERROR_STATUS_CODES[hsError.name] || 500\n );\n }\n\n if (error instanceof Error) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('unknown_error', sanitized, 1);\n }\n\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n}\n","import { auth } from './auth.js';\nimport { HelpScoutCliError, HelpScoutApiError } from './errors.js';\nimport dotenv from 'dotenv';\nimport type {\n Conversation,\n Customer,\n Tag,\n Workflow,\n Mailbox,\n Thread,\n PageInfo,\n} from '../types/index.js';\n\ndotenv.config();\n\nconst API_BASE = 'https://api.helpscout.net/v2';\nconst TOKEN_URL = 'https://api.helpscout.net/v2/oauth2/token';\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n token_type: string;\n expires_in: number;\n}\n\ninterface PaginatedResponse<T> {\n _embedded: T;\n page: PageInfo;\n}\n\nexport class HelpScoutClient {\n private accessToken: string | null = null;\n\n clearToken(): void {\n this.accessToken = null;\n }\n\n async refreshAccessToken(): Promise<string> {\n const appId = await auth.getAppId();\n const appSecret = await auth.getAppSecret();\n const refreshToken = await auth.getRefreshToken();\n\n if (!appId || !appSecret) {\n throw new HelpScoutCliError('Not configured. Please run: helpscout auth login', 401);\n }\n\n if (refreshToken) {\n try {\n const response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: appId,\n client_secret: appSecret,\n refresh_token: refreshToken,\n }),\n });\n\n if (response.ok) {\n const data = (await response.json()) as TokenResponse;\n await auth.setAccessToken(data.access_token);\n if (data.refresh_token) {\n await auth.setRefreshToken(data.refresh_token);\n }\n this.accessToken = data.access_token;\n return data.access_token;\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(\n JSON.stringify({\n warning: 'Refresh token failed, using client credentials',\n reason: message,\n })\n );\n }\n }\n\n let response: Response;\n try {\n response = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: appId,\n client_secret: appSecret,\n }),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown network error';\n throw new HelpScoutCliError(`Network request failed during authentication: ${message}`, 0);\n }\n\n if (!response.ok) {\n const error = await response.json();\n throw new HelpScoutApiError('OAuth token request failed', error, response.status);\n }\n\n const data = (await response.json()) as TokenResponse;\n await auth.setAccessToken(data.access_token);\n this.accessToken = data.access_token;\n return data.access_token;\n }\n\n async getAccessToken(): Promise<string> {\n if (this.accessToken) {\n return this.accessToken;\n }\n\n const storedToken = await auth.getAccessToken();\n if (storedToken) {\n this.accessToken = storedToken;\n return storedToken;\n }\n\n return this.refreshAccessToken();\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: {\n params?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n retry?: boolean;\n rateLimitRetry?: boolean;\n } = {}\n ): Promise<T> {\n const { params, body, retry = true, rateLimitRetry = true } = options;\n\n const url = new URL(`${API_BASE}${path}`);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n\n const token = await this.getAccessToken();\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n };\n if (body) {\n fetchOptions.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url.toString(), fetchOptions);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown network error';\n throw new HelpScoutCliError(`Network request failed: ${message}`, 0);\n }\n\n if (response.status === 401 && retry) {\n this.accessToken = null;\n await this.refreshAccessToken();\n return this.request(method, path, { ...options, retry: false });\n }\n\n if (response.status === 429 && rateLimitRetry) {\n const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);\n const waitSeconds = Math.min(retryAfter, 120);\n console.error(\n JSON.stringify({ warning: `Rate limited. Waiting ${waitSeconds}s before retry...` })\n );\n await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));\n return this.request(method, path, { ...options, rateLimitRetry: false });\n }\n\n if (response.status === 204) {\n return {} as T;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new HelpScoutApiError('API request failed', error, response.status);\n }\n\n return response.json() as Promise<T>;\n }\n\n // Conversations\n async listConversations(\n params: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: number;\n embed?: string;\n query?: string;\n } = {}\n ) {\n const response = await this.request<PaginatedResponse<{ conversations: Conversation[] }>>(\n 'GET',\n '/conversations',\n { params }\n );\n return {\n conversations: response._embedded?.conversations || [],\n page: response.page,\n };\n }\n\n async listAllConversations(\n params: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n query?: string;\n } = {}\n ): Promise<Conversation[]> {\n const allConversations: Conversation[] = [];\n let page = 1;\n let totalPages = 1;\n\n do {\n const result = await this.listConversations({ ...params, page });\n allConversations.push(...result.conversations);\n totalPages = result.page.totalPages;\n page++;\n } while (page <= totalPages);\n\n return allConversations;\n }\n\n async getConversation(conversationId: number, embed?: string) {\n const params = embed ? { embed } : undefined;\n return this.request<Conversation>('GET', `/conversations/${conversationId}`, { params });\n }\n\n async getConversationThreads(conversationId: number) {\n const response = await this.request<PaginatedResponse<{ threads: Thread[] }>>(\n 'GET',\n `/conversations/${conversationId}/threads`\n );\n return response._embedded?.threads || [];\n }\n\n async updateConversation(\n conversationId: number,\n data: Partial<{\n op: string;\n path: string;\n value: unknown;\n }>\n ) {\n await this.request<void>('PATCH', `/conversations/${conversationId}`, { body: data });\n }\n\n async deleteConversation(conversationId: number) {\n await this.request<void>('DELETE', `/conversations/${conversationId}`);\n }\n\n async addConversationTag(conversationId: number, tag: string) {\n await this.request<void>('PUT', `/conversations/${conversationId}/tags`, {\n body: { tags: [tag] },\n });\n }\n\n async removeConversationTag(conversationId: number, tag: string) {\n const conversation = await this.getConversation(conversationId);\n const existingTags = conversation?.tags?.map((t) => t.name) || [];\n const newTags = existingTags.filter((t) => t !== tag);\n await this.request<void>('PUT', `/conversations/${conversationId}/tags`, {\n body: { tags: newTags },\n });\n }\n\n async createReply(\n conversationId: number,\n data: {\n text: string;\n user?: number;\n draft?: boolean;\n status?: string;\n }\n ) {\n await this.request<void>('POST', `/conversations/${conversationId}/reply`, { body: data });\n }\n\n async createNote(\n conversationId: number,\n data: {\n text: string;\n user?: number;\n }\n ) {\n await this.request<void>('POST', `/conversations/${conversationId}/notes`, { body: data });\n }\n\n // Customers\n async listCustomers(\n params: {\n mailbox?: string;\n firstName?: string;\n lastName?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: number;\n query?: string;\n } = {}\n ) {\n const response = await this.request<PaginatedResponse<{ customers: Customer[] }>>(\n 'GET',\n '/customers',\n { params }\n );\n return {\n customers: response._embedded?.customers || [],\n page: response.page,\n };\n }\n\n async getCustomer(customerId: number) {\n return this.request<Customer>('GET', `/customers/${customerId}`);\n }\n\n async createCustomer(data: {\n firstName?: string;\n lastName?: string;\n emails?: Array<{ type: string; value: string }>;\n phones?: Array<{ type: string; value: string }>;\n }) {\n await this.request<void>('POST', '/customers', { body: data });\n }\n\n async updateCustomer(\n customerId: number,\n data: Partial<{\n firstName: string;\n lastName: string;\n jobTitle: string;\n location: string;\n organization: string;\n background: string;\n }>\n ) {\n await this.request<void>('PUT', `/customers/${customerId}`, { body: data });\n }\n\n async deleteCustomer(customerId: number) {\n await this.request<void>('DELETE', `/customers/${customerId}`);\n }\n\n // Tags\n async listTags(page?: number) {\n const response = await this.request<PaginatedResponse<{ tags: Tag[] }>>('GET', '/tags', {\n params: page ? { page } : undefined,\n });\n return {\n tags: response._embedded?.tags || [],\n page: response.page,\n };\n }\n\n async getTag(tagId: number) {\n return this.request<Tag>('GET', `/tags/${tagId}`);\n }\n\n // Workflows\n async listWorkflows(\n params: {\n mailbox?: number;\n type?: string;\n page?: number;\n } = {}\n ) {\n const response = await this.request<PaginatedResponse<{ workflows: Workflow[] }>>(\n 'GET',\n '/workflows',\n { params: { mailboxId: params.mailbox, type: params.type, page: params.page } }\n );\n return {\n workflows: response._embedded?.workflows || [],\n page: response.page,\n };\n }\n\n async runWorkflow(workflowId: number, conversationIds: number[]) {\n await this.request<void>('POST', `/workflows/${workflowId}/run`, {\n body: { conversationIds },\n });\n }\n\n async updateWorkflowStatus(workflowId: number, status: 'active' | 'inactive') {\n await this.request<void>('PATCH', `/workflows/${workflowId}`, {\n body: { op: 'replace', path: '/status', value: status },\n });\n }\n\n // Mailboxes\n async listMailboxes(page?: number) {\n const response = await this.request<PaginatedResponse<{ mailboxes: Mailbox[] }>>(\n 'GET',\n '/mailboxes',\n { params: page ? { page } : undefined }\n );\n return {\n mailboxes: response._embedded?.mailboxes || [],\n page: response.page,\n };\n }\n\n async getMailbox(mailboxId: number) {\n return this.request<Mailbox>('GET', `/mailboxes/${mailboxId}`);\n }\n}\n\nexport const client = new HelpScoutClient();\n","import { handleHelpScoutError, HelpScoutCliError } from './errors.js';\nimport { outputJson } from './output.js';\n\nexport function withErrorHandling<T extends unknown[], R>(\n fn: (...args: T) => Promise<R>\n): (...args: T) => Promise<void> {\n return async (...args: T) => {\n try {\n await fn(...args);\n } catch (error) {\n handleHelpScoutError(error);\n }\n };\n}\n\nexport function parseIdArg(value: string, resourceType: string = 'resource'): number {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed) || parsed <= 0) {\n throw new HelpScoutCliError(`Invalid ${resourceType} ID: \"${value}\"`, 400);\n }\n return parsed;\n}\n\nexport function requireAtLeastOneField(data: Record<string, unknown>, operation: string): void {\n const hasFields = Object.values(data).some((v) => v !== undefined);\n if (!hasFields) {\n throw new HelpScoutCliError(`${operation} requires at least one field to update`, 400);\n }\n}\n\nexport async function confirmDelete(\n resourceType: string,\n skipConfirmation?: boolean\n): Promise<boolean> {\n if (skipConfirmation) {\n return true;\n }\n\n const readline = await import('readline');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(`Delete ${resourceType}? (y/N) `, (answer) => {\n rl.close();\n if (answer.toLowerCase() !== 'y') {\n outputJson({ cancelled: true, message: 'Deletion cancelled' });\n process.exit(0);\n }\n resolve(true);\n });\n });\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createMailboxesCommand(): Command {\n const cmd = new Command('mailboxes').description('Mailbox operations');\n\n cmd\n .command('list')\n .description('List mailboxes')\n .option('--page <number>', 'Page number')\n .action(\n withErrorHandling(async (options: { page?: string }) => {\n const result = await client.listMailboxes(\n options.page ? parseInt(options.page, 10) : undefined\n );\n outputJson(result);\n })\n );\n\n cmd\n .command('view')\n .description('View a mailbox')\n .argument('<id>', 'Mailbox ID')\n .action(\n withErrorHandling(async (id: string) => {\n const mailbox = await client.getMailbox(parseIdArg(id, 'mailbox'));\n outputJson(mailbox);\n })\n );\n\n cmd\n .command('set-default')\n .description('Set default mailbox')\n .argument('<id>', 'Mailbox ID')\n .action(\n withErrorHandling(async (id: string) => {\n const mailboxId = parseIdArg(id, 'mailbox');\n config.setDefaultMailbox(String(mailboxId));\n outputJson({ message: `Default mailbox set to ${mailboxId}` });\n })\n );\n\n cmd\n .command('get-default')\n .description('Get default mailbox')\n .action(\n withErrorHandling(async () => {\n const mailboxId = config.getDefaultMailbox();\n outputJson({ defaultMailbox: mailboxId || null });\n })\n );\n\n cmd\n .command('clear-default')\n .description('Clear default mailbox')\n .action(\n withErrorHandling(async () => {\n config.clearDefaultMailbox();\n outputJson({ message: 'Default mailbox cleared' });\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, confirmDelete, parseIdArg } from '../lib/command-utils.js';\nimport type { Conversation } from '../types/index.js';\n\ninterface ConversationSummary {\n total: number;\n byStatus: Record<string, number>;\n byTag: Record<string, number>;\n conversations: Array<{\n id: number;\n subject: string;\n status: string;\n tags: string[];\n preview: string;\n }>;\n}\n\nfunction summarizeConversations(conversations: Conversation[]): ConversationSummary {\n const byStatus: Record<string, number> = {};\n const byTag: Record<string, number> = {};\n\n for (const conv of conversations) {\n byStatus[conv.status] = (byStatus[conv.status] || 0) + 1;\n\n for (const tag of conv.tags || []) {\n byTag[tag.name] = (byTag[tag.name] || 0) + 1;\n }\n }\n\n return {\n total: conversations.length,\n byStatus,\n byTag,\n conversations: conversations.map((c) => ({\n id: c.id,\n subject: c.subject,\n status: c.status,\n tags: (c.tags || []).map((t) => t.name),\n preview: c.preview,\n })),\n };\n}\n\nexport function createConversationsCommand(): Command {\n const cmd = new Command('conversations').description('Conversation operations');\n\n cmd\n .command('list')\n .description('List conversations')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('-s, --status <status>', 'Filter by status (active, all, closed, open, pending, spam)')\n .option('-t, --tag <tags>', 'Filter by tag(s), comma-separated')\n .option('--assigned-to <id>', 'Filter by assignee user ID')\n .option('--modified-since <date>', 'Filter by modified date (ISO 8601)')\n .option(\n '--sort-field <field>',\n 'Sort by field (createdAt, modifiedAt, number, status, subject)'\n )\n .option('--sort-order <order>', 'Sort order (asc, desc)')\n .option('--page <number>', 'Page number')\n .option('--embed <resources>', 'Embed resources (threads)')\n .option(\n '-q, --query <query>',\n 'Advanced search query (see https://docs.helpscout.com/article/47-search-filters-with-operators)'\n )\n .option('--summary', 'Output aggregated summary instead of full conversation list')\n .action(\n withErrorHandling(\n async (options: {\n mailbox?: string;\n status?: string;\n tag?: string;\n assignedTo?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: string;\n embed?: string;\n query?: string;\n summary?: boolean;\n }) => {\n if (options.summary) {\n const allConversations = await client.listAllConversations({\n mailbox: options.mailbox,\n status: options.status,\n tag: options.tag,\n assignedTo: options.assignedTo,\n modifiedSince: options.modifiedSince,\n query: options.query,\n });\n const summary = summarizeConversations(allConversations);\n outputJson(summary);\n return;\n }\n\n const result = await client.listConversations({\n mailbox: options.mailbox,\n status: options.status,\n tag: options.tag,\n assignedTo: options.assignedTo,\n modifiedSince: options.modifiedSince,\n sortField: options.sortField,\n sortOrder: options.sortOrder,\n page: options.page ? parseInt(options.page, 10) : undefined,\n embed: options.embed,\n query: options.query,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View a conversation')\n .argument('<id>', 'Conversation ID')\n .option('--embed <resources>', 'Embed resources (threads)')\n .action(\n withErrorHandling(async (id: string, options: { embed?: string }) => {\n const conversation = await client.getConversation(\n parseIdArg(id, 'conversation'),\n options.embed\n );\n outputJson(conversation);\n })\n );\n\n cmd\n .command('threads')\n .description('List threads for a conversation (defaults to email communications only)')\n .argument('<id>', 'Conversation ID')\n .option('--include-notes', 'Include internal notes')\n .option('--all', 'Show all thread types including lineitems, workflows, etc.')\n .option(\n '-t, --type <types>',\n 'Filter by specific thread type(s), comma-separated (customer, message, note, lineitem, chat, phone, forwardchild, forwardparent, beaconchat)'\n )\n .action(\n withErrorHandling(\n async (id: string, options: { includeNotes?: boolean; all?: boolean; type?: string }) => {\n let threads = await client.getConversationThreads(parseIdArg(id, 'conversation'));\n\n if (options.type) {\n const types = options.type.split(',').map((t) => t.trim().toLowerCase());\n threads = threads.filter((t) => types.includes(t.type));\n } else if (!options.all) {\n const allowedTypes = options.includeNotes\n ? ['customer', 'message', 'note', 'chat', 'phone']\n : ['customer', 'message', 'chat', 'phone'];\n threads = threads.filter((t) => allowedTypes.includes(t.type));\n }\n\n outputJson(threads);\n }\n )\n );\n\n cmd\n .command('delete')\n .description('Delete a conversation')\n .argument('<id>', 'Conversation ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(async (id: string, options: { yes?: boolean }) => {\n await confirmDelete('conversation', options.yes);\n await client.deleteConversation(parseIdArg(id, 'conversation'));\n outputJson({ message: 'Conversation deleted' });\n })\n );\n\n cmd\n .command('add-tag')\n .description('Add a tag to a conversation')\n .argument('<id>', 'Conversation ID')\n .argument('<tag>', 'Tag name')\n .action(\n withErrorHandling(async (id: string, tag: string) => {\n await client.addConversationTag(parseIdArg(id, 'conversation'), tag);\n outputJson({ message: `Tag \"${tag}\" added` });\n })\n );\n\n cmd\n .command('remove-tag')\n .description('Remove a tag from a conversation')\n .argument('<id>', 'Conversation ID')\n .argument('<tag>', 'Tag name')\n .action(\n withErrorHandling(async (id: string, tag: string) => {\n await client.removeConversationTag(parseIdArg(id, 'conversation'), tag);\n outputJson({ message: `Tag \"${tag}\" removed` });\n })\n );\n\n cmd\n .command('reply')\n .description('Reply to a conversation')\n .argument('<id>', 'Conversation ID')\n .requiredOption('--text <text>', 'Reply text')\n .option('--user <id>', 'User ID sending the reply')\n .option('--draft', 'Save as draft')\n .option('--status <status>', 'Set conversation status after reply (active, closed, pending)')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n text: string;\n user?: string;\n draft?: boolean;\n status?: string;\n }\n ) => {\n await client.createReply(parseIdArg(id, 'conversation'), {\n text: options.text,\n user: options.user ? parseIdArg(options.user, 'user') : undefined,\n draft: options.draft,\n status: options.status,\n });\n outputJson({ message: 'Reply sent' });\n }\n )\n );\n\n cmd\n .command('note')\n .description('Add a note to a conversation')\n .argument('<id>', 'Conversation ID')\n .requiredOption('--text <text>', 'Note text')\n .option('--user <id>', 'User ID adding the note')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n text: string;\n user?: string;\n }\n ) => {\n await client.createNote(parseIdArg(id, 'conversation'), {\n text: options.text,\n user: options.user ? parseIdArg(options.user, 'user') : undefined,\n });\n outputJson({ message: 'Note added' });\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport {\n withErrorHandling,\n confirmDelete,\n parseIdArg,\n requireAtLeastOneField,\n} from '../lib/command-utils.js';\n\nexport function createCustomersCommand(): Command {\n const cmd = new Command('customers').description('Customer operations');\n\n cmd\n .command('list')\n .description('List customers')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('--first-name <name>', 'Filter by first name')\n .option('--last-name <name>', 'Filter by last name')\n .option('--modified-since <date>', 'Filter by modified date (ISO 8601)')\n .option('--sort-field <field>', 'Sort by field (createdAt, firstName, lastName, modifiedAt)')\n .option('--sort-order <order>', 'Sort order (asc, desc)')\n .option('--page <number>', 'Page number')\n .option('-q, --query <query>', 'Advanced search query')\n .action(\n withErrorHandling(\n async (options: {\n mailbox?: string;\n firstName?: string;\n lastName?: string;\n modifiedSince?: string;\n sortField?: string;\n sortOrder?: string;\n page?: string;\n query?: string;\n }) => {\n const result = await client.listCustomers({\n mailbox: options.mailbox,\n firstName: options.firstName,\n lastName: options.lastName,\n modifiedSince: options.modifiedSince,\n sortField: options.sortField,\n sortOrder: options.sortOrder,\n page: options.page ? parseInt(options.page, 10) : undefined,\n query: options.query,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View a customer')\n .argument('<id>', 'Customer ID')\n .action(\n withErrorHandling(async (id: string) => {\n const customer = await client.getCustomer(parseIdArg(id, 'customer'));\n outputJson(customer);\n })\n );\n\n cmd\n .command('create')\n .description('Create a customer')\n .option('--first-name <name>', 'First name')\n .option('--last-name <name>', 'Last name')\n .option('--email <email>', 'Email address')\n .option('--phone <phone>', 'Phone number')\n .action(\n withErrorHandling(\n async (options: {\n firstName?: string;\n lastName?: string;\n email?: string;\n phone?: string;\n }) => {\n const data = {\n ...(options.firstName && { firstName: options.firstName }),\n ...(options.lastName && { lastName: options.lastName }),\n ...(options.email && { emails: [{ type: 'work', value: options.email }] }),\n ...(options.phone && { phones: [{ type: 'work', value: options.phone }] }),\n };\n requireAtLeastOneField(data, 'Customer create');\n await client.createCustomer(data);\n outputJson({ message: 'Customer created' });\n }\n )\n );\n\n cmd\n .command('update')\n .description('Update a customer')\n .argument('<id>', 'Customer ID')\n .option('--first-name <name>', 'First name')\n .option('--last-name <name>', 'Last name')\n .option('--job-title <title>', 'Job title')\n .option('--location <location>', 'Location')\n .option('--organization <org>', 'Organization')\n .option('--background <text>', 'Background notes')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n firstName?: string;\n lastName?: string;\n jobTitle?: string;\n location?: string;\n organization?: string;\n background?: string;\n }\n ) => {\n const data = {\n ...(options.firstName && { firstName: options.firstName }),\n ...(options.lastName && { lastName: options.lastName }),\n ...(options.jobTitle && { jobTitle: options.jobTitle }),\n ...(options.location && { location: options.location }),\n ...(options.organization && { organization: options.organization }),\n ...(options.background && { background: options.background }),\n };\n requireAtLeastOneField(data, 'Customer update');\n await client.updateCustomer(parseIdArg(id, 'customer'), data);\n outputJson({ message: 'Customer updated' });\n }\n )\n );\n\n cmd\n .command('delete')\n .description('Delete a customer')\n .argument('<id>', 'Customer ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(async (id: string, options: { yes?: boolean }) => {\n await confirmDelete('customer', options.yes);\n await client.deleteCustomer(parseIdArg(id, 'customer'));\n outputJson({ message: 'Customer deleted' });\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createTagsCommand(): Command {\n const cmd = new Command('tags').description('Tag operations');\n\n cmd\n .command('list')\n .description('List all tags')\n .option('--page <number>', 'Page number')\n .action(\n withErrorHandling(async (options: { page?: string }) => {\n const result = await client.listTags(options.page ? parseInt(options.page, 10) : undefined);\n outputJson(result);\n })\n );\n\n cmd\n .command('view')\n .description('View a tag')\n .argument('<id>', 'Tag ID')\n .action(\n withErrorHandling(async (id: string) => {\n const tag = await client.getTag(parseIdArg(id, 'tag'));\n outputJson(tag);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, parseIdArg } from '../lib/command-utils.js';\n\nexport function createWorkflowsCommand(): Command {\n const cmd = new Command('workflows').description('Workflow operations');\n\n cmd\n .command('list')\n .description('List workflows')\n .option('-m, --mailbox <id>', 'Filter by mailbox ID')\n .option('-t, --type <type>', 'Filter by type (manual, automatic)')\n .option('--page <number>', 'Page number')\n .action(\n withErrorHandling(\n async (options: {\n mailbox?: string;\n type?: string;\n page?: string;\n }) => {\n const result = await client.listWorkflows({\n mailbox: options.mailbox ? parseIdArg(options.mailbox, 'mailbox') : undefined,\n type: options.type,\n page: options.page ? parseInt(options.page, 10) : undefined,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('run')\n .description('Run a manual workflow on conversations')\n .argument('<workflow-id>', 'Workflow ID')\n .requiredOption('--conversations <ids>', 'Comma-separated conversation IDs')\n .action(\n withErrorHandling(async (workflowId: string, options: { conversations: string }) => {\n const conversationIds = options.conversations\n .split(',')\n .map((id) => parseIdArg(id.trim(), 'conversation'));\n await client.runWorkflow(parseIdArg(workflowId, 'workflow'), conversationIds);\n outputJson({ message: 'Workflow executed' });\n })\n );\n\n cmd\n .command('activate')\n .description('Activate a workflow')\n .argument('<id>', 'Workflow ID')\n .action(\n withErrorHandling(async (id: string) => {\n await client.updateWorkflowStatus(parseIdArg(id, 'workflow'), 'active');\n outputJson({ message: 'Workflow activated' });\n })\n );\n\n cmd\n .command('deactivate')\n .description('Deactivate a workflow')\n .argument('<id>', 'Workflow ID')\n .action(\n withErrorHandling(async (id: string) => {\n await client.updateWorkflowStatus(parseIdArg(id, 'workflow'), 'inactive');\n outputJson({ message: 'Workflow deactivated' });\n })\n );\n\n return cmd;\n}\n"],"mappings":"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","names":["Command","result","response","data","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephendolan/helpscout-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A command-line interface for Help Scout",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",
@@ -11,7 +11,9 @@
11
11
  "dev": "tsx src/cli.ts",
12
12
  "build": "tsup",
13
13
  "test": "vitest",
14
- "lint": "eslint src --ext .ts",
14
+ "lint": "oxlint src",
15
+ "format": "biome format --write src",
16
+ "format:check": "biome format src",
15
17
  "typecheck": "tsc --noEmit",
16
18
  "link": "npm run build && npm link",
17
19
  "start": "node dist/cli.js",
@@ -51,10 +53,9 @@
51
53
  "html-to-text": "^9.0.5"
52
54
  },
53
55
  "devDependencies": {
56
+ "@biomejs/biome": "^1.9.4",
54
57
  "@types/node": "^20.0.0",
55
- "@typescript-eslint/eslint-plugin": "^6.0.0",
56
- "@typescript-eslint/parser": "^6.0.0",
57
- "eslint": "^8.56.0",
58
+ "oxlint": "^0.16.0",
58
59
  "tsup": "^8.0.0",
59
60
  "tsx": "^4.7.0",
60
61
  "typescript": "^5.3.0",