@tplog/zendcli 0.2.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +5 -5
  2. package/dist/cli.js +204 -143
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -30,7 +30,7 @@ This is the recommended option for temporary or CI usage.
30
30
 
31
31
  ```bash
32
32
  export ZENDESK_SUBDOMAIN="your-subdomain"
33
- export ZENDESK_EMAIL="you@example.com"
33
+ export ZENDESK_EMAIL="foo@example.com"
34
34
  export ZENDESK_API_TOKEN="your_zendesk_api_token"
35
35
  ```
36
36
 
@@ -46,11 +46,11 @@ zend follower --help
46
46
  zend comments --help
47
47
  zend tickets --limit 10
48
48
  zend tickets --status open --limit 20
49
- zend email user@example.com
50
- zend email user@example.com --status unresolved
51
- zend email user@example.com --status open,pending
49
+ zend email foo@example.com
50
+ zend email foo@example.com --status unresolved
51
+ zend email foo@example.com --status open,pending
52
52
  zend follower
53
- zend follower tp@dify.ai --limit 3
53
+ zend follower foo@example.com --limit 3
54
54
  zend comments 12345
55
55
  zend comments 12345 --type public
56
56
  zend comments 12345 --json
package/dist/cli.js CHANGED
@@ -3512,29 +3512,42 @@ function getConfig() {
3512
3512
  }
3513
3513
 
3514
3514
  // src/api.ts
3515
- function getAuthHeader() {
3515
+ var ApiError = class extends Error {
3516
+ status;
3517
+ body;
3518
+ constructor(message, status, body) {
3519
+ super(message);
3520
+ this.name = "ApiError";
3521
+ this.status = status;
3522
+ this.body = body;
3523
+ }
3524
+ };
3525
+ function authHeader() {
3516
3526
  const { email, api_token } = getConfig();
3517
3527
  const credentials = btoa(`${email}/token:${api_token}`);
3518
3528
  return `Basic ${credentials}`;
3519
3529
  }
3520
3530
  async function fetchJson(url) {
3521
- const resp = await fetch(url, {
3522
- headers: { Authorization: getAuthHeader() }
3523
- });
3531
+ let resp;
3532
+ try {
3533
+ resp = await fetch(url, {
3534
+ headers: { Authorization: authHeader() }
3535
+ });
3536
+ } catch (error) {
3537
+ const message = error instanceof Error ? error.message : "Network request failed";
3538
+ throw new ApiError(message);
3539
+ }
3524
3540
  if (!resp.ok) {
3525
3541
  const body = await resp.text();
3526
- console.error(`Error ${resp.status}: ${body}`);
3527
- process.exit(1);
3542
+ throw new ApiError(`HTTP ${resp.status}`, resp.status, body);
3528
3543
  }
3529
3544
  return resp.json();
3530
3545
  }
3531
3546
  async function apiGet(path, params) {
3532
3547
  const { subdomain } = getConfig();
3533
3548
  const url = new URL(`https://${subdomain}.zendesk.com${path}`);
3534
- if (params) {
3535
- for (const [key, value] of Object.entries(params)) {
3536
- url.searchParams.set(key, String(value));
3537
- }
3549
+ for (const [key, value] of Object.entries(params || {})) {
3550
+ url.searchParams.set(key, String(value));
3538
3551
  }
3539
3552
  return fetchJson(url.toString());
3540
3553
  }
@@ -3545,7 +3558,55 @@ async function apiGetUrl(url) {
3545
3558
  // src/cli.ts
3546
3559
  var program2 = new Command();
3547
3560
  var VALID_TICKET_STATUSES = ["new", "open", "pending", "hold", "solved", "closed"];
3548
- program2.name("zend").description("Zendesk tickets & comments CLI").version("0.1.0");
3561
+ var KNOWN_COMMANDS = /* @__PURE__ */ new Set(["configure", "follower", "comments", "help", "email", "ticket"]);
3562
+ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3563
+ var DIGITS_RE = /^\d+$/;
3564
+ var CliError = class extends Error {
3565
+ code;
3566
+ details;
3567
+ exitCode;
3568
+ constructor(code, message, details = {}, exitCode = 1) {
3569
+ super(message);
3570
+ this.name = "CliError";
3571
+ this.code = code;
3572
+ this.details = details;
3573
+ this.exitCode = exitCode;
3574
+ }
3575
+ };
3576
+ program2.name("zend").description("Zendesk tickets CLI").version("2.0.0");
3577
+ function printJson(value) {
3578
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
3579
+ `);
3580
+ }
3581
+ function fail(code, message, details = {}, exitCode = 1) {
3582
+ printJson({ error: code, message, ...details });
3583
+ process.exit(exitCode);
3584
+ }
3585
+ function handleError(error) {
3586
+ if (error instanceof CliError) {
3587
+ fail(error.code, error.message, error.details, error.exitCode);
3588
+ }
3589
+ if (error instanceof ApiError) {
3590
+ if (error.status === 401) {
3591
+ fail("auth_failed", "401 Unauthorized", { status: 401 });
3592
+ }
3593
+ if (error.status === 404) {
3594
+ fail("not_found", "Resource not found", { status: 404 });
3595
+ }
3596
+ fail("api_error", error.body || error.message, error.status ? { status: error.status } : {});
3597
+ }
3598
+ const message = error instanceof Error ? error.message : "Unknown error";
3599
+ fail("unknown_error", message);
3600
+ }
3601
+ function run(fn) {
3602
+ return async (...args) => {
3603
+ try {
3604
+ await fn(...args);
3605
+ } catch (error) {
3606
+ handleError(error);
3607
+ }
3608
+ };
3609
+ }
3549
3610
  function prompt(question, defaultValue = "") {
3550
3611
  return new Promise((resolve) => {
3551
3612
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
@@ -3562,199 +3623,199 @@ function promptHidden(question, hasDefault = false) {
3562
3623
  const stdout = process.stderr;
3563
3624
  let value = "";
3564
3625
  readline.emitKeypressEvents(stdin);
3565
- if (stdin.isTTY) {
3566
- stdin.setRawMode(true);
3567
- }
3568
- const suffix = hasDefault ? " [****]" : "";
3569
- stdout.write(`${question}${suffix}: `);
3626
+ if (stdin.isTTY) stdin.setRawMode(true);
3627
+ stdout.write(`${question}${hasDefault ? " [****]" : ""}: `);
3570
3628
  const onKeypress = (char, key) => {
3571
3629
  if (key.name === "return" || key.name === "enter") {
3572
3630
  stdout.write("\n");
3573
3631
  stdin.off("keypress", onKeypress);
3574
- if (stdin.isTTY) {
3575
- stdin.setRawMode(false);
3576
- }
3632
+ if (stdin.isTTY) stdin.setRawMode(false);
3577
3633
  resolve(value);
3578
3634
  return;
3579
3635
  }
3580
3636
  if (key.ctrl && key.name === "c") {
3581
3637
  stdout.write("\n");
3582
3638
  stdin.off("keypress", onKeypress);
3583
- if (stdin.isTTY) {
3584
- stdin.setRawMode(false);
3585
- }
3639
+ if (stdin.isTTY) stdin.setRawMode(false);
3586
3640
  process.exit(130);
3587
3641
  }
3588
3642
  if (key.name === "backspace") {
3589
3643
  value = value.slice(0, -1);
3590
3644
  return;
3591
3645
  }
3592
- if (char) {
3593
- value += char;
3594
- }
3646
+ if (char) value += char;
3595
3647
  };
3596
3648
  stdin.on("keypress", onKeypress);
3597
3649
  });
3598
3650
  }
3599
- function parseStatusFilter(input) {
3600
- if (!input) return [];
3651
+ function parseStatusFilter(input = "unresolved") {
3601
3652
  const statuses = input.split(",").map((value) => value.trim().toLowerCase()).filter(Boolean);
3602
3653
  const invalid = statuses.filter((status) => status !== "unresolved" && status !== "all" && !VALID_TICKET_STATUSES.includes(status));
3603
3654
  if (invalid.length > 0) {
3604
- console.error(`Invalid status value(s): ${invalid.join(", ")}`);
3605
- console.error(`Allowed values: unresolved, all, ${VALID_TICKET_STATUSES.join(", ")}`);
3606
- process.exit(1);
3655
+ throw new CliError("invalid_args", `Invalid status value(s): ${invalid.join(", ")}`, { input });
3607
3656
  }
3608
3657
  if (statuses.includes("all")) return [];
3609
3658
  if (statuses.includes("unresolved")) return ["new", "open", "pending", "hold"];
3610
3659
  return statuses;
3611
3660
  }
3612
- function buildSearchQuery(base, rawStatus, statusFilter, canUseSearchStatus) {
3613
- let query = base;
3614
- if (rawStatus === "unresolved") {
3615
- query += " status<solved";
3616
- } else if (canUseSearchStatus && statusFilter.length === 1) {
3617
- query += ` status:${statusFilter[0]}`;
3661
+ function parseLimit(input = "20") {
3662
+ const limit = Number.parseInt(input, 10);
3663
+ if (!Number.isFinite(limit) || Number.isNaN(limit)) {
3664
+ throw new CliError("invalid_args", "limit must be an integer", { limit: input });
3618
3665
  }
3619
- return query;
3666
+ if (limit < 1 || limit > 100) {
3667
+ throw new CliError("invalid_args", "limit must be between 1 and 100", { limit });
3668
+ }
3669
+ return limit;
3620
3670
  }
3621
- function printTickets(tickets, meta) {
3622
- for (const t of tickets) {
3623
- const status = (t.status || "").padEnd(8);
3624
- const subject = t.subject || "(no subject)";
3625
- console.log(`[${t.id}] ${status} ${subject}`);
3626
- console.log(meta(t));
3627
- console.log();
3671
+ function parseSort(input = "desc") {
3672
+ if (input !== "asc" && input !== "desc") {
3673
+ throw new CliError("invalid_args", "sort must be asc or desc", { sort: input });
3628
3674
  }
3675
+ return input;
3676
+ }
3677
+ function buildSearchQuery(base, rawStatus, statusFilter) {
3678
+ if (rawStatus === "unresolved") return `${base} status<solved`;
3679
+ if (statusFilter.length === 1) return `${base} status:${statusFilter[0]}`;
3680
+ return base;
3681
+ }
3682
+ function filterStatuses(tickets, rawStatus, statusFilter) {
3683
+ if (rawStatus === "unresolved" || statusFilter.length <= 1) return tickets;
3684
+ return tickets.filter((ticket) => statusFilter.includes(String(ticket.status || "").toLowerCase()));
3629
3685
  }
3630
3686
  async function findUserByEmail(email) {
3631
- const data = await apiGet("/api/v2/users/search.json", {
3632
- query: email
3633
- });
3634
- const user = (data.users || []).find((item) => item.email?.toLowerCase() === email.toLowerCase()) || data.users?.[0];
3635
- if (!user) {
3636
- console.error(`No Zendesk user found for email: ${email}`);
3637
- process.exit(1);
3638
- }
3639
- return user;
3687
+ const data = await apiGet("/api/v2/users/search.json", { query: email });
3688
+ const users = data.users || [];
3689
+ const exact = users.find((user) => user.email?.toLowerCase() === email.toLowerCase());
3690
+ if (exact) return exact;
3691
+ if (users[0]) return users[0];
3692
+ throw new CliError("user_not_found", `No Zendesk user found for email: ${email}`, { email });
3640
3693
  }
3641
- async function findFollowerTickets(email, rawStatus, limit, sort) {
3694
+ async function fetchFollowerTickets(email, rawStatus, limit, sort) {
3642
3695
  const user = await findUserByEmail(email);
3643
3696
  const statusFilter = parseStatusFilter(rawStatus);
3644
- const canUseSearchStatus = rawStatus === "unresolved" || statusFilter.length === 1;
3645
- let url = new URL(`https://${getConfig().subdomain}.zendesk.com/api/v2/search.json`).toString();
3646
- const params = new URLSearchParams({
3647
- query: buildSearchQuery("type:ticket", rawStatus, statusFilter, canUseSearchStatus),
3648
- sort_by: "updated_at",
3649
- sort_order: sort,
3650
- per_page: "100"
3651
- });
3652
- url += `?${params.toString()}`;
3697
+ const baseUrl = new URL(`${apiBaseUrl()}/api/v2/search.json`);
3698
+ baseUrl.searchParams.set("query", buildSearchQuery("type:ticket", rawStatus, statusFilter));
3699
+ baseUrl.searchParams.set("sort_by", "updated_at");
3700
+ baseUrl.searchParams.set("sort_order", sort);
3701
+ baseUrl.searchParams.set("per_page", "100");
3653
3702
  const matches = [];
3654
- while (url && matches.length < limit) {
3655
- const data = await apiGetUrl(url);
3656
- let tickets = data.results || [];
3657
- if (statusFilter.length > 0 && rawStatus !== "unresolved" && !canUseSearchStatus) {
3658
- tickets = tickets.filter((ticket) => statusFilter.includes((ticket.status || "").toLowerCase()));
3659
- }
3703
+ let nextUrl = baseUrl.toString();
3704
+ while (nextUrl && matches.length < limit) {
3705
+ const data = await apiGetUrl(nextUrl);
3706
+ const tickets = filterStatuses(data.results || [], rawStatus, statusFilter);
3660
3707
  for (const ticket of tickets) {
3661
- const followers = ticket.follower_ids || [];
3662
- if (followers.includes(user.id) && ticket.assignee_id !== user.id) {
3708
+ if ((ticket.follower_ids || []).includes(user.id) && ticket.assignee_id !== user.id) {
3663
3709
  matches.push(ticket);
3664
3710
  }
3665
- if (matches.length >= limit) {
3666
- break;
3667
- }
3711
+ if (matches.length >= limit) break;
3668
3712
  }
3669
- url = data.next_page || null;
3713
+ nextUrl = data.next_page || null;
3670
3714
  }
3671
3715
  return matches;
3672
3716
  }
3673
- program2.command("configure").description("Set up Zendesk credentials interactively").action(async () => {
3717
+ function apiBaseUrl() {
3718
+ const { subdomain } = getConfig();
3719
+ return `https://${subdomain}.zendesk.com`;
3720
+ }
3721
+ program2.command("configure").description("Set up Zendesk credentials interactively").action(run(async () => {
3674
3722
  const existing = loadConfig();
3675
- console.error("Zendesk CLI Configuration");
3676
- console.error("\u2500".repeat(30));
3723
+ process.stderr.write("Zendesk CLI Configuration\n");
3724
+ process.stderr.write(`${"\u2500".repeat(30)}
3725
+ `);
3677
3726
  const subdomain = await prompt("Subdomain (xxx.zendesk.com)", existing.subdomain);
3678
3727
  const email = await prompt("Email", existing.email);
3679
3728
  const tokenInput = await promptHidden("API Token", Boolean(existing.api_token));
3680
3729
  const api_token = tokenInput || existing.api_token || "";
3681
3730
  saveConfig({ subdomain, email, api_token });
3682
- console.error("\nSaved to ~/.zendcli/config.json with restricted permissions (0600)");
3683
- console.error("Environment variables also work: ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_API_TOKEN");
3684
- });
3685
- program2.command("tickets").description("List tickets from Zendesk, sorted by updated_at").option("--status <status>", "Filter by status (new|open|pending|hold|solved|closed)").option("--limit <n>", "Max tickets to return", "20").option("--sort <order>", "Sort order (asc|desc)", "desc").action(async (opts) => {
3686
- const limit = parseInt(opts.limit, 10);
3687
- const data = await apiGet("/api/v2/tickets.json", {
3688
- per_page: Math.min(limit, 100),
3689
- sort_order: opts.sort,
3690
- sort_by: "updated_at"
3691
- });
3692
- let tickets = data.tickets || [];
3693
- if (opts.status) {
3694
- tickets = tickets.filter((t) => t.status === opts.status);
3731
+ printJson({ ok: true });
3732
+ }));
3733
+ var TICKET_SUMMARY_FIELDS = [
3734
+ "id",
3735
+ "subject",
3736
+ "description",
3737
+ "status",
3738
+ "priority",
3739
+ "created_at",
3740
+ "updated_at",
3741
+ "tags",
3742
+ "requester_id",
3743
+ "assignee_id",
3744
+ "collaborator_ids",
3745
+ "follower_ids",
3746
+ "organization_id",
3747
+ "group_id",
3748
+ "type",
3749
+ "via",
3750
+ "url"
3751
+ ];
3752
+ function pickTicketFields(ticket) {
3753
+ const result = {};
3754
+ for (const key of TICKET_SUMMARY_FIELDS) {
3755
+ if (key in ticket) result[key] = ticket[key];
3695
3756
  }
3696
- printTickets(tickets.slice(0, limit), (ticket) => {
3697
- return ` priority=${ticket.priority ?? "-"} type=${ticket.type ?? "-"} created=${ticket.created_at}`;
3698
- });
3699
- });
3700
- program2.command("email <email>").description("Find tickets for a requester email").option("--status <status>", "Filter status: unresolved|all|new|open|pending|hold|solved|closed or comma-separated list", "unresolved").option("--limit <n>", "Max tickets to return", "20").option("--sort <order>", "Sort order (asc|desc)", "desc").option("--json", "Output raw JSON").action(async (email, opts) => {
3701
- const limit = parseInt(opts.limit, 10);
3757
+ return result;
3758
+ }
3759
+ program2.command("ticket <id>").description("Get a single ticket").option("--raw", "Output full API response without field filtering").action(run(async (id, opts) => {
3760
+ if (!DIGITS_RE.test(id)) {
3761
+ throw new CliError("invalid_args", "ticket id must be numeric", { id });
3762
+ }
3763
+ try {
3764
+ const data = await apiGet(`/api/v2/tickets/${id}.json`);
3765
+ if (!data.ticket) {
3766
+ throw new CliError("not_found", `Ticket ${id} not found`, { id: Number(id) });
3767
+ }
3768
+ printJson(opts.raw ? data.ticket : pickTicketFields(data.ticket));
3769
+ } catch (error) {
3770
+ if (error instanceof ApiError && error.status === 404) {
3771
+ fail("not_found", `Ticket ${id} not found`, { id: Number(id) });
3772
+ }
3773
+ throw error;
3774
+ }
3775
+ }));
3776
+ program2.command("email <email>").description("Find tickets for an assignee email").option("--status <status>", "unresolved|all|new|open|pending|hold|solved|closed or comma-separated list", "unresolved").option("--limit <n>", "Max tickets to return", "20").option("--sort <order>", "Sort order (asc|desc)", "desc").action(run(async (email, opts) => {
3777
+ const limit = parseLimit(opts.limit);
3778
+ const sort = parseSort(opts.sort);
3702
3779
  const statusFilter = parseStatusFilter(opts.status);
3703
- const canUseSearchStatus = opts.status === "unresolved" || statusFilter.length === 1;
3704
- const query = buildSearchQuery(`type:ticket requester:${email}`, opts.status, statusFilter, canUseSearchStatus);
3780
+ const query = buildSearchQuery(`type:ticket assignee:${email}`, opts.status, statusFilter);
3705
3781
  const data = await apiGet("/api/v2/search.json", {
3706
3782
  query,
3707
3783
  sort_by: "updated_at",
3708
- sort_order: opts.sort,
3784
+ sort_order: sort,
3709
3785
  per_page: 100
3710
3786
  });
3711
- let tickets = data.results || [];
3712
- if (statusFilter.length > 0 && opts.status !== "unresolved" && !canUseSearchStatus) {
3713
- tickets = tickets.filter((ticket) => statusFilter.includes((ticket.status || "").toLowerCase()));
3787
+ const tickets = filterStatuses(data.results || [], opts.status, statusFilter).slice(0, limit);
3788
+ printJson(tickets);
3789
+ }));
3790
+ program2.command("follower <email>").description("Find tickets where the user is a follower but not the assignee").option("--status <status>", "unresolved|all|new|open|pending|hold|solved|closed or comma-separated list", "unresolved").option("--limit <n>", "Max tickets to return", "20").option("--sort <order>", "Sort order (asc|desc)", "desc").action(run(async (email, opts) => {
3791
+ const limit = parseLimit(opts.limit);
3792
+ const sort = parseSort(opts.sort);
3793
+ const tickets = await fetchFollowerTickets(email, opts.status, limit, sort);
3794
+ printJson(tickets);
3795
+ }));
3796
+ program2.command("comments <ticketId>").description("List comments for a ticket").option("--type <type>", "all|public|internal", "all").option("--sort <order>", "Sort order (asc|desc)", "asc").action(run(async (ticketId, opts) => {
3797
+ if (!DIGITS_RE.test(ticketId)) {
3798
+ throw new CliError("invalid_args", "ticket id must be numeric", { ticketId });
3714
3799
  }
3715
- tickets = tickets.slice(0, limit);
3716
- if (opts.json) {
3717
- console.log(JSON.stringify(tickets, null, 2));
3718
- return;
3719
- }
3720
- printTickets(tickets, (ticket) => {
3721
- return ` priority=${ticket.priority ?? "-"} type=${ticket.type ?? "-"} requester=${email} updated=${ticket.updated_at}`;
3722
- });
3723
- });
3724
- program2.command("follower [email]").description("Find tickets where the user is a follower but not the assignee").option("--status <status>", "Filter status: unresolved|all|new|open|pending|hold|solved|closed or comma-separated list", "unresolved").option("--limit <n>", "Max tickets to return", "20").option("--sort <order>", "Sort order (asc|desc)", "desc").option("--json", "Output raw JSON").action(async (email, opts) => {
3725
- const targetEmail = email || getConfig().email;
3726
- const limit = parseInt(opts.limit, 10);
3727
- const tickets = await findFollowerTickets(targetEmail, opts.status, limit, opts.sort);
3728
- if (opts.json) {
3729
- console.log(JSON.stringify(tickets, null, 2));
3730
- return;
3800
+ const sort = parseSort(opts.sort);
3801
+ if (!["all", "public", "internal"].includes(opts.type)) {
3802
+ throw new CliError("invalid_args", "type must be all, public, or internal", { type: opts.type });
3731
3803
  }
3732
- printTickets(tickets, (ticket) => {
3733
- return ` priority=${ticket.priority ?? "-"} type=${ticket.type ?? "-"} follower=${targetEmail} assignee=${ticket.assignee_id ?? "-"} updated=${ticket.updated_at}`;
3734
- });
3735
- });
3736
- program2.command("comments <ticketId>").description("List comments/thread for a ticket (public=customer-facing, internal=agents only)").option("--type <type>", "Filter: all|public|internal", "all").option("--sort <order>", "Sort order (asc|desc)", "asc").option("--json", "Output raw JSON").action(async (ticketId, opts) => {
3737
3804
  const data = await apiGet(
3738
3805
  `/api/v2/tickets/${ticketId}/comments.json`,
3739
- { sort_order: opts.sort, per_page: 100 }
3806
+ { sort_order: sort, per_page: 100 }
3740
3807
  );
3741
3808
  let comments = data.comments || [];
3742
- if (opts.type === "public") {
3743
- comments = comments.filter((c) => c.public === true);
3744
- } else if (opts.type === "internal") {
3745
- comments = comments.filter((c) => c.public === false);
3746
- }
3747
- if (opts.json) {
3748
- console.log(JSON.stringify(comments, null, 2));
3749
- return;
3750
- }
3751
- for (const c of comments) {
3752
- const label = c.public ? "PUBLIC" : "INTERNAL";
3753
- const via = c.via?.channel ?? "?";
3754
- console.log(`--- [${label}] id=${c.id} author=${c.author_id} via=${via} ${c.created_at} ---`);
3755
- const body = (c.plain_body || c.body || "").trim();
3756
- console.log(body);
3757
- console.log();
3758
- }
3759
- });
3809
+ if (opts.type === "public") comments = comments.filter((comment) => comment.public === true);
3810
+ if (opts.type === "internal") comments = comments.filter((comment) => comment.public === false);
3811
+ printJson(comments);
3812
+ }));
3813
+ function preprocessArgv(argv) {
3814
+ const firstArg = argv[2];
3815
+ if (!firstArg || firstArg.startsWith("-") || KNOWN_COMMANDS.has(firstArg)) return argv;
3816
+ if (EMAIL_RE.test(firstArg)) return [...argv.slice(0, 2), "email", ...argv.slice(2)];
3817
+ if (DIGITS_RE.test(firstArg)) return [...argv.slice(0, 2), "ticket", ...argv.slice(2)];
3818
+ return argv;
3819
+ }
3820
+ process.argv = preprocessArgv(process.argv);
3760
3821
  program2.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tplog/zendcli",
3
- "version": "0.2.3",
3
+ "version": "1.1.0",
4
4
  "description": "Minimal Zendesk CLI for tickets and comments",
5
5
  "repository": {
6
6
  "type": "git",