bamboohr-cli 1.0.21 → 1.0.22-g6336787.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +108 -61
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -60,33 +60,77 @@ function readPackageVersion(importMetaUrl) {
60
60
 
61
61
  // ../../cli-utils/dist/validators.js
62
62
  import { InvalidArgumentError } from "commander";
63
+ function nonNegativeInt(raw) {
64
+ const n = parseInt(raw, 10);
65
+ if (Number.isNaN(n) || n < 0) {
66
+ throw new InvalidArgumentError("Must be a non-negative integer.");
67
+ }
68
+ return n;
69
+ }
63
70
  function positiveInt(raw) {
64
71
  const n = parseInt(raw, 10);
65
72
  if (Number.isNaN(n) || n < 1) {
66
- throw new InvalidArgumentError(`Must be a positive integer (got "${raw}")`);
73
+ throw new InvalidArgumentError("Must be a positive integer.");
67
74
  }
68
75
  return n;
69
76
  }
77
+ function text(raw) {
78
+ return raw;
79
+ }
80
+ function date(raw) {
81
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw);
82
+ if (!m) {
83
+ throw new InvalidArgumentError("Must be a date in YYYY-MM-DD format.");
84
+ }
85
+ const [, y, mo, d] = m;
86
+ const year = Number(y);
87
+ const month = Number(mo);
88
+ const day = Number(d);
89
+ const dt = new Date(Date.UTC(year, month - 1, day));
90
+ if (dt.getUTCFullYear() !== year || dt.getUTCMonth() !== month - 1 || dt.getUTCDate() !== day) {
91
+ throw new InvalidArgumentError("Not a real calendar date.");
92
+ }
93
+ return raw;
94
+ }
95
+
96
+ // ../../cli-utils/dist/json.js
97
+ import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
98
+ function jsonShape(schema) {
99
+ return (raw) => {
100
+ let parsed;
101
+ try {
102
+ parsed = JSON.parse(raw);
103
+ } catch {
104
+ throw new InvalidArgumentError2("Must be valid JSON.");
105
+ }
106
+ const result = schema.safeParse(parsed);
107
+ if (!result.success) {
108
+ const issues = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
109
+ throw new InvalidArgumentError2(`Invalid JSON shape \u2014 ${issues}`);
110
+ }
111
+ return result.data;
112
+ };
113
+ }
70
114
 
71
115
  // ../../cli-utils/dist/text-or-file.js
72
116
  import { readFileSync as readFileSync3 } from "fs";
73
- import { InvalidArgumentError as InvalidArgumentError2, Option } from "commander";
117
+ import { InvalidArgumentError as InvalidArgumentError3, Option } from "commander";
74
118
  var STDIN_REF = "-";
75
119
  function rejectStdinSentinel(value) {
76
120
  if (value === "@-" || value === STDIN_REF) {
77
- throw new InvalidArgumentError2(`"${value}" looks like a stdin redirect, which is not supported here. Pass the text directly, or read it from a file/stdin with the matching --\u2026-file <path|-> option.`);
121
+ throw new InvalidArgumentError3(`"${value}" looks like a stdin redirect, which is not supported here. Pass the text directly, or read it from a file/stdin with the matching --\u2026-file <path|-> option.`);
78
122
  }
79
123
  return value;
80
124
  }
81
125
  function readFileOrStdin(ref) {
82
126
  if (ref === STDIN_REF) {
83
127
  if (process.stdin.isTTY) {
84
- throw new InvalidArgumentError2('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
128
+ throw new InvalidArgumentError3('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
85
129
  }
86
130
  try {
87
131
  return readFileSync3(0, "utf8");
88
132
  } catch (err) {
89
- throw new InvalidArgumentError2(`failed to read stdin for "--\u2026-file -": ${err.message}`);
133
+ throw new InvalidArgumentError3(`failed to read stdin for "--\u2026-file -": ${err.message}`);
90
134
  }
91
135
  }
92
136
  try {
@@ -94,28 +138,28 @@ function readFileOrStdin(ref) {
94
138
  } catch (err) {
95
139
  const e = err;
96
140
  if (e.code === "ENOENT") {
97
- throw new InvalidArgumentError2(`file not found: "${ref}".`);
141
+ throw new InvalidArgumentError3(`file not found: "${ref}".`);
98
142
  }
99
- throw new InvalidArgumentError2(`failed to read file "${ref}": ${e.message}`);
143
+ throw new InvalidArgumentError3(`failed to read file "${ref}": ${e.message}`);
100
144
  }
101
145
  }
102
146
  function textOrFileOption(cmd, name, opts = {}) {
103
147
  const label = `${name.charAt(0).toUpperCase()}${name.slice(1)} content`;
104
148
  cmd.option(`--${name} <text>`, opts.description ?? label, rejectStdinSentinel);
105
- cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name));
149
+ cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name).argParser(text));
106
150
  return cmd;
107
151
  }
108
152
  function resolveTextOrFile(opts, name, { required = true } = {}) {
109
153
  const literal = opts[name];
110
154
  const ref = opts[`${name}File`];
111
155
  if (literal !== void 0 && ref !== void 0) {
112
- throw new InvalidArgumentError2(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
156
+ throw new InvalidArgumentError3(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
113
157
  }
114
158
  if (ref !== void 0) {
115
159
  return readFileOrStdin(ref);
116
160
  }
117
161
  if (literal === void 0 && required) {
118
- throw new InvalidArgumentError2(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
162
+ throw new InvalidArgumentError3(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
119
163
  }
120
164
  return literal;
121
165
  }
@@ -518,7 +562,7 @@ function directory(parent) {
518
562
 
519
563
  // src/commands/employee/get.ts
520
564
  function get(parent) {
521
- const cmd = parent.command("get [employeeId]").description("Get employee data by ID (default: current user)").option("--fields <fields>", "Comma-separated field names", "firstName,lastName,email,jobTitle").option("--include-future", "Include future-dated values from history fields").option("--with-photos", "Include the employee's signed photo URL and photoUploaded flag");
565
+ const cmd = parent.command("get").description("Get employee data by ID (default: current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).option("--fields <fields>", "Comma-separated field names", text, "firstName,lastName,email,jobTitle").option("--include-future", "Include future-dated values from history fields").option("--with-photos", "Include the employee's signed photo URL and photoUploaded flag");
522
566
  examples(cmd, [
523
567
  "",
524
568
  "123",
@@ -531,7 +575,7 @@ function get(parent) {
531
575
  const client = getClient();
532
576
  const fields2 = opts.withPhotos ? mergeFields(opts.fields, ["photoUrl", "photoUploaded"]) : opts.fields;
533
577
  const result = await client.employees.get({
534
- id: employeeId ?? "0",
578
+ id: employeeId !== void 0 ? String(employeeId) : "0",
535
579
  fields: fields2,
536
580
  onlyCurrent: !opts.includeFuture
537
581
  });
@@ -551,12 +595,12 @@ function mergeFields(existing, extra) {
551
595
  import { Option as Option2 } from "commander";
552
596
  var GOAL_FILTERS = ["open", "closed", "all"];
553
597
  function goals(parent) {
554
- const cmd = parent.command("goals <employeeId>").description("Get employee performance goals").addOption(new Option2("--filter <filter>", "Filter goals by status").choices(GOAL_FILTERS).default("all"));
598
+ const cmd = parent.command("goals").description("Get employee performance goals").argument("<employeeId>", "Employee ID (0 = current user)", nonNegativeInt).addOption(new Option2("--filter <filter>", "Filter goals by status").choices(GOAL_FILTERS).default("all"));
555
599
  examples(cmd, ["123", ["123 --filter open", "only open goals"], ["123 --filter closed", "only closed goals"]]);
556
600
  cmd.action(async (employeeId, opts) => {
557
601
  const client = getClient();
558
602
  const result = await client.goals.get({
559
- employeeId,
603
+ employeeId: String(employeeId),
560
604
  filter: opts.filter === "all" ? void 0 : opts.filter
561
605
  });
562
606
  output(transformGoals(result));
@@ -568,12 +612,12 @@ import { writeFileSync as writeFileSync2 } from "fs";
568
612
  import { Option as Option3 } from "commander";
569
613
  var PHOTO_SIZES = ["original", "large", "medium", "small", "xs", "tiny"];
570
614
  function photo(parent) {
571
- const cmd = parent.command("photo <employeeId>").description("Download employee photo").requiredOption("--output <path>", "File path to save photo").addOption(new Option3("--size <size>", "Photo size").choices(PHOTO_SIZES).default("medium"));
615
+ const cmd = parent.command("photo").description("Download employee photo").argument("<employeeId>", "Employee ID (0 = current user)", nonNegativeInt).requiredOption("--output <path>", "File path to save photo", text).addOption(new Option3("--size <size>", "Photo size").choices(PHOTO_SIZES).default("medium"));
572
616
  examples(cmd, [["123 --output ./photo.jpg", "medium size (default)"], "123 --output ./photo.jpg --size large"]);
573
617
  cmd.action(async (employeeId, opts) => {
574
618
  const client = getClient();
575
619
  const buffer = await client.employees.getPhoto({
576
- employeeId,
620
+ employeeId: String(employeeId),
577
621
  size: opts.size
578
622
  });
579
623
  writeFileSync2(opts.output, buffer);
@@ -590,7 +634,7 @@ async function resolveEmployeeId(client, employeeId) {
590
634
 
591
635
  // src/commands/employee/search.ts
592
636
  function search(parent) {
593
- const cmd = parent.command("search [query]").description("Search and filter employees").option("--supervisor <name>", 'Filter by supervisor name (use "me" for current user)').option("--department <name>", "Filter by department").option("--location <name>", "Filter by location").option("--division <name>", "Filter by division").option("--with-photos", "Include each result's signed photo URL and photoUploaded flag");
637
+ const cmd = parent.command("search").description("Search and filter employees").argument("[query]", "Name fragment to search for", text).option("--supervisor <name>", 'Filter by supervisor name (use "me" for current user)', text).option("--department <name>", "Filter by department", text).option("--location <name>", "Filter by location", text).option("--division <name>", "Filter by division", text).option("--with-photos", "Include each result's signed photo URL and photoUploaded flag");
594
638
  examples(cmd, [
595
639
  "john",
596
640
  "--supervisor me",
@@ -657,11 +701,11 @@ function registerEmployeeCommands(program) {
657
701
  // src/commands/file/get.ts
658
702
  import { writeFileSync as writeFileSync3 } from "fs";
659
703
  function get2(parent) {
660
- const cmd = parent.command("get <fileId>").description("Download a company file").requiredOption("--output <path>", "File path to save to");
704
+ const cmd = parent.command("get").description("Download a company file").argument("<fileId>", "File ID", positiveInt).requiredOption("--output <path>", "File path to save to", text);
661
705
  examples(cmd, ["42 --output ./handbook.pdf"]);
662
706
  cmd.action(async (fileId, opts) => {
663
707
  const client = getClient();
664
- const buffer = await client.files.get({ fileId });
708
+ const buffer = await client.files.get({ fileId: String(fileId) });
665
709
  writeFileSync3(opts.output, buffer);
666
710
  output({ saved: true, path: opts.output, size: buffer.length });
667
711
  });
@@ -745,59 +789,43 @@ function registerMetaCommands(program) {
745
789
 
746
790
  // src/commands/timeoff/balance.ts
747
791
  function balance(parent) {
748
- const cmd = parent.command("balance [employeeId]").description("Estimate time off balance (defaults to current user)").option("--date <date>", "Future date to estimate balance for (YYYY-MM-DD)");
792
+ const cmd = parent.command("balance").description("Estimate time off balance (defaults to current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).option("--date <date>", "Future date to estimate balance for (YYYY-MM-DD)", date);
749
793
  examples(cmd, ["", "123", ["--date 2026-06-30", "balance at a future date"]]);
750
794
  cmd.action(async (employeeId, opts) => {
751
795
  const client = getClient();
752
- const id = await resolveEmployeeId(client, employeeId);
796
+ const id = await resolveEmployeeId(client, employeeId !== void 0 ? String(employeeId) : void 0);
753
797
  const result = await client.timeOff.getBalance({ employeeId: id, date: opts.date });
754
798
  output(transformTimeOffBalances(result));
755
799
  });
756
800
  }
757
801
 
758
802
  // src/commands/timeoff/create.ts
759
- import { InvalidArgumentError as InvalidArgumentError4, Option as Option4 } from "commander";
803
+ import { InvalidArgumentError as InvalidArgumentError5, Option as Option4 } from "commander";
804
+ import { z } from "zod";
760
805
 
761
806
  // src/utils/timeoff-dates.ts
762
- import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
807
+ import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
763
808
  var WEEKDAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
764
809
  var YMD = /^\d{4}-\d{2}-\d{2}$/;
765
- function parseDatesJson(raw) {
766
- let parsed;
767
- try {
768
- parsed = JSON.parse(raw);
769
- } catch {
770
- throw new InvalidArgumentError3(
771
- `--dates is not valid JSON. Expected an array like '[{"ymd":"2026-03-21","amount":0.5}]'.`
772
- );
773
- }
774
- const isEntry = (d) => typeof d === "object" && d !== null && typeof d.ymd === "string" && YMD.test(d.ymd) && typeof d.amount === "number" && Number.isFinite(d.amount) && d.amount >= 0;
775
- if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(isEntry)) {
776
- throw new InvalidArgumentError3(
777
- '--dates must be a non-empty JSON array of {"ymd":"YYYY-MM-DD","amount":<non-negative number>} objects.'
778
- );
779
- }
780
- return parsed.map((d) => ({ ymd: d.ymd, amount: d.amount }));
781
- }
782
810
  function parseYmd(value, label) {
783
811
  if (!YMD.test(value)) {
784
- throw new InvalidArgumentError3(`${label} must be a YYYY-MM-DD date, got "${value}".`);
812
+ throw new InvalidArgumentError4(`${label} must be a YYYY-MM-DD date, got "${value}".`);
785
813
  }
786
- const date = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
787
- if (Number.isNaN(date.getTime())) {
788
- throw new InvalidArgumentError3(`${label} is not a valid date: "${value}".`);
814
+ const date2 = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
815
+ if (Number.isNaN(date2.getTime())) {
816
+ throw new InvalidArgumentError4(`${label} is not a valid date: "${value}".`);
789
817
  }
790
- return date;
818
+ return date2;
791
819
  }
792
- function toYmd(date) {
793
- return date.toISOString().slice(0, 10);
820
+ function toYmd(date2) {
821
+ return date2.toISOString().slice(0, 10);
794
822
  }
795
823
  function buildTimeOffDates(params) {
796
824
  const { start, end, units, defaultHours, holidays = [] } = params;
797
825
  const startDate = parseYmd(start, "--start-date");
798
826
  const endDate = parseYmd(end, "--end-date");
799
827
  if (endDate < startDate) {
800
- throw new InvalidArgumentError3(`--end-date ${end} is before --start-date ${start}.`);
828
+ throw new InvalidArgumentError4(`--end-date ${end} is before --start-date ${start}.`);
801
829
  }
802
830
  const hoursByName = new Map(defaultHours.map((entry) => [entry.name, Number(entry.amount)]));
803
831
  const fallbackHours = hoursByName.get("default") ?? 8;
@@ -813,12 +841,31 @@ function buildTimeOffDates(params) {
813
841
  }
814
842
 
815
843
  // src/commands/timeoff/create.ts
844
+ var datesSchema = z.array(
845
+ z.object({
846
+ // Reuse the shared `date` validator so an impossible calendar date (e.g. 2026-02-30)
847
+ // is rejected inside --dates JSON exactly as it is for --start-date/--end-date.
848
+ ymd: z.string().refine(
849
+ (v) => {
850
+ try {
851
+ date(v);
852
+ return true;
853
+ } catch {
854
+ return false;
855
+ }
856
+ },
857
+ { message: "must be a real YYYY-MM-DD date" }
858
+ ),
859
+ amount: z.number().finite().nonnegative()
860
+ })
861
+ ).min(1, "must be a non-empty array");
816
862
  function create(parent) {
817
- const cmd = parent.command("create [employeeId]").description("Create a time off request (defaults to current user)").requiredOption("--start-date <date>", "Start date (YYYY-MM-DD)").requiredOption("--end-date <date>", "End date (YYYY-MM-DD)").requiredOption("--type-id <id>", 'Time off type ID (use "timeoff types" to find IDs)', positiveInt).addOption(
863
+ const cmd = parent.command("create").description("Create a time off request (defaults to current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).requiredOption("--start-date <date>", "Start date (YYYY-MM-DD)", date).requiredOption("--end-date <date>", "End date (YYYY-MM-DD)", date).requiredOption("--type-id <id>", 'Time off type ID (use "timeoff types" to find IDs)', positiveInt).addOption(
818
864
  new Option4("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
819
865
  ).option(
820
866
  "--dates <json>",
821
- `Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":0.5}]' for a half day. When omitted, generated automatically: 1 day (or the weekday's working hours) per working day, 0 on weekends and company holidays`
867
+ `Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":0.5}]' for a half day. When omitted, generated automatically: 1 day (or the weekday's working hours) per working day, 0 on weekends and company holidays`,
868
+ jsonShape(datesSchema)
822
869
  );
823
870
  textOrFileOption(cmd, "note", { description: "Note to include with the request" });
824
871
  examples(cmd, [
@@ -835,11 +882,11 @@ function create(parent) {
835
882
  cmd.action(
836
883
  async (employeeId, opts) => {
837
884
  const client = getClient();
838
- const id = await resolveEmployeeId(client, employeeId);
885
+ const id = await resolveEmployeeId(client, employeeId !== void 0 ? String(employeeId) : void 0);
839
886
  const note = resolveTextOrFile(opts, "note", { required: false });
840
887
  let dates;
841
888
  if (opts.dates) {
842
- dates = parseDatesJson(opts.dates);
889
+ dates = opts.dates;
843
890
  } else {
844
891
  const [types2, whosOut2] = await Promise.all([
845
892
  getTimeOffTypes(client),
@@ -847,7 +894,7 @@ function create(parent) {
847
894
  ]);
848
895
  const type = types2.timeOffTypes.find((t) => Number(t.id) === opts.typeId);
849
896
  if (!type) {
850
- throw new InvalidArgumentError4(`Unknown time off type ID ${opts.typeId}. Run "timeoff types" to list IDs.`);
897
+ throw new InvalidArgumentError5(`Unknown time off type ID ${opts.typeId}. Run "timeoff types" to list IDs.`);
851
898
  }
852
899
  const holidays = whosOut2.filter((e) => e.type === "holiday").map((e) => ({ start: e.start, end: e.end }));
853
900
  dates = buildTimeOffDates({
@@ -860,7 +907,7 @@ function create(parent) {
860
907
  }
861
908
  const total = dates.reduce((sum, d) => sum + d.amount, 0);
862
909
  if (total <= 0) {
863
- throw new InvalidArgumentError4(
910
+ throw new InvalidArgumentError5(
864
911
  opts.dates ? "The per-day amounts in --dates sum to 0; a request must claim more than 0 days/hours." : "The requested range contains no working days (weekends/company holidays only). Adjust the dates or pass --dates explicitly."
865
912
  );
866
913
  }
@@ -884,7 +931,7 @@ function create(parent) {
884
931
  // src/commands/timeoff/requests.ts
885
932
  import { Option as Option5 } from "commander";
886
933
  function requests(parent) {
887
- const cmd = parent.command("requests").description("Get time off requests (defaults to current user)").option("--request-id <id>", "Specific request ID", positiveInt).addOption(new Option5("--action <action>", "Access level filter").choices(["view", "approve"])).option("--employee-id <id>", "Filter by employee ID").option("--all", "Show all visible requests instead of just current user").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").addOption(
934
+ const cmd = parent.command("requests").description("Get time off requests (defaults to current user)").option("--request-id <id>", "Specific request ID", positiveInt).addOption(new Option5("--action <action>", "Access level filter").choices(["view", "approve"])).option("--employee-id <id>", "Filter by employee ID (0 = current user)", nonNegativeInt).option("--all", "Show all visible requests instead of just current user").option("--start-date <date>", "Start date (YYYY-MM-DD)", date).option("--end-date <date>", "End date (YYYY-MM-DD)", date).addOption(
888
935
  new Option5("--status <status>", "Filter by request status").choices([
889
936
  "approved",
890
937
  "denied",
@@ -892,7 +939,7 @@ function requests(parent) {
892
939
  "requested",
893
940
  "canceled"
894
941
  ])
895
- ).option("--type-id <typeId>", "Filter by time off type ID");
942
+ ).option("--type-id <typeId>", "Filter by time off type ID", positiveInt);
896
943
  examples(cmd, [
897
944
  "",
898
945
  "--status requested",
@@ -905,7 +952,7 @@ function requests(parent) {
905
952
  const start = opts.startDate ?? `${year}-01-01`;
906
953
  const end = opts.endDate ?? `${year}-12-31`;
907
954
  const client = getClient();
908
- let employeeId = opts.employeeId;
955
+ let employeeId = opts.employeeId !== void 0 ? String(opts.employeeId) : void 0;
909
956
  if (!employeeId && !opts.all) {
910
957
  employeeId = await resolveEmployeeId(client);
911
958
  }
@@ -916,7 +963,7 @@ function requests(parent) {
916
963
  start,
917
964
  end,
918
965
  status: opts.status,
919
- type: opts.typeId
966
+ type: opts.typeId !== void 0 ? String(opts.typeId) : void 0
920
967
  });
921
968
  output(transformTimeOffRequests(result));
922
969
  }
@@ -937,7 +984,7 @@ function types(parent) {
937
984
  // src/commands/timeoff/update-status.ts
938
985
  import { Option as Option6 } from "commander";
939
986
  function updateStatus(parent) {
940
- const cmd = parent.command("update-status <requestId>").description("Update time off request status (approve, deny, cancel)").addOption(
987
+ const cmd = parent.command("update-status").description("Update time off request status (approve, deny, cancel)").argument("<requestId>", "Time off request ID", positiveInt).addOption(
941
988
  new Option6("--status <status>", "New status").choices(["approved", "denied", "canceled"]).makeOptionMandatory()
942
989
  );
943
990
  textOrFileOption(cmd, "note", { description: "Note to attach to the status change" });
@@ -951,7 +998,7 @@ function updateStatus(parent) {
951
998
  const client = getClient();
952
999
  const note = resolveTextOrFile(opts, "note", { required: false });
953
1000
  const result = await client.timeOff.updateRequestStatus({
954
- requestId,
1001
+ requestId: String(requestId),
955
1002
  status: opts.status,
956
1003
  note
957
1004
  });
@@ -962,7 +1009,7 @@ function updateStatus(parent) {
962
1009
 
963
1010
  // src/commands/timeoff/whos-out.ts
964
1011
  function whosOut(parent) {
965
- const cmd = parent.command("whos-out").description("View who's out \u2014 upcoming time off and holidays").option("--start-date <date>", "Start date (YYYY-MM-DD, defaults to today)").option("--end-date <date>", "End date (YYYY-MM-DD, defaults to today)");
1012
+ const cmd = parent.command("whos-out").description("View who's out \u2014 upcoming time off and holidays").option("--start-date <date>", "Start date (YYYY-MM-DD, defaults to today)", date).option("--end-date <date>", "End date (YYYY-MM-DD, defaults to today)", date);
966
1013
  examples(cmd, ["", ["--start-date 2026-03-20 --end-date 2026-04-03", "two-week window"]]);
967
1014
  cmd.action(async (opts) => {
968
1015
  const client = getClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bamboohr-cli",
3
- "version": "1.0.21",
3
+ "version": "1.0.22-g6336787.1",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,8 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "bamboohr-client": "1.0.24"
15
+ "zod": "^3.25.67",
16
+ "bamboohr-client": "1.0.24-g6336787.1"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@types/node": "24.10.4",