bamboohr-cli 1.0.19 → 1.0.20

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 +81 -23
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -68,6 +68,58 @@ function positiveInt(raw) {
68
68
  return n;
69
69
  }
70
70
 
71
+ // ../../cli-utils/dist/text-or-file.js
72
+ import { readFileSync as readFileSync3 } from "fs";
73
+ import { InvalidArgumentError as InvalidArgumentError2, Option } from "commander";
74
+ var STDIN_REF = "-";
75
+ function rejectStdinSentinel(value) {
76
+ 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.`);
78
+ }
79
+ return value;
80
+ }
81
+ function readFileOrStdin(ref) {
82
+ if (ref === STDIN_REF) {
83
+ if (process.stdin.isTTY) {
84
+ throw new InvalidArgumentError2('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
85
+ }
86
+ try {
87
+ return readFileSync3(0, "utf8");
88
+ } catch (err) {
89
+ throw new InvalidArgumentError2(`failed to read stdin for "--\u2026-file -": ${err.message}`);
90
+ }
91
+ }
92
+ try {
93
+ return readFileSync3(ref, "utf8");
94
+ } catch (err) {
95
+ const e = err;
96
+ if (e.code === "ENOENT") {
97
+ throw new InvalidArgumentError2(`file not found: "${ref}".`);
98
+ }
99
+ throw new InvalidArgumentError2(`failed to read file "${ref}": ${e.message}`);
100
+ }
101
+ }
102
+ function textOrFileOption(cmd, name, opts = {}) {
103
+ const label = `${name.charAt(0).toUpperCase()}${name.slice(1)} content`;
104
+ 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));
106
+ return cmd;
107
+ }
108
+ function resolveTextOrFile(opts, name, { required = true } = {}) {
109
+ const literal = opts[name];
110
+ const ref = opts[`${name}File`];
111
+ if (literal !== void 0 && ref !== void 0) {
112
+ throw new InvalidArgumentError2(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
113
+ }
114
+ if (ref !== void 0) {
115
+ return readFileOrStdin(ref);
116
+ }
117
+ if (literal === void 0 && required) {
118
+ throw new InvalidArgumentError2(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
119
+ }
120
+ return literal;
121
+ }
122
+
71
123
  // ../../cli-utils/dist/builders.js
72
124
  var EXAMPLES = /* @__PURE__ */ new WeakSet();
73
125
  function commandPath(cmd) {
@@ -496,10 +548,10 @@ function mergeFields(existing, extra) {
496
548
  }
497
549
 
498
550
  // src/commands/employee/goals.ts
499
- import { Option } from "commander";
551
+ import { Option as Option2 } from "commander";
500
552
  var GOAL_FILTERS = ["open", "closed", "all"];
501
553
  function goals(parent) {
502
- const cmd = parent.command("goals <employeeId>").description("Get employee performance goals").addOption(new Option("--filter <filter>", "Filter goals by status").choices(GOAL_FILTERS).default("all"));
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"));
503
555
  examples(cmd, ["123", ["123 --filter open", "only open goals"], ["123 --filter closed", "only closed goals"]]);
504
556
  cmd.action(async (employeeId, opts) => {
505
557
  const client = getClient();
@@ -513,10 +565,10 @@ function goals(parent) {
513
565
 
514
566
  // src/commands/employee/photo.ts
515
567
  import { writeFileSync as writeFileSync2 } from "fs";
516
- import { Option as Option2 } from "commander";
568
+ import { Option as Option3 } from "commander";
517
569
  var PHOTO_SIZES = ["original", "large", "medium", "small", "xs", "tiny"];
518
570
  function photo(parent) {
519
- const cmd = parent.command("photo <employeeId>").description("Download employee photo").requiredOption("--output <path>", "File path to save photo").addOption(new Option2("--size <size>", "Photo size").choices(PHOTO_SIZES).default("medium"));
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"));
520
572
  examples(cmd, [["123 --output ./photo.jpg", "medium size (default)"], "123 --output ./photo.jpg --size large"]);
521
573
  cmd.action(async (employeeId, opts) => {
522
574
  const client = getClient();
@@ -704,11 +756,12 @@ function balance(parent) {
704
756
  }
705
757
 
706
758
  // src/commands/timeoff/create.ts
707
- import { Option as Option3 } from "commander";
759
+ import { Option as Option4 } from "commander";
708
760
  function create(parent) {
709
761
  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).requiredOption("--amount <amount>", "Total amount of time off (in days or hours depending on type)", parseFloat).addOption(
710
- new Option3("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
711
- ).option("--note <text>", "Note to include with the request").option("--dates <json>", `Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":4}]' for half-day`);
762
+ new Option4("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
763
+ ).option("--dates <json>", `Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":4}]' for half-day`);
764
+ textOrFileOption(cmd, "note", { description: "Note to include with the request" });
712
765
  examples(cmd, [
713
766
  "--start-date 2026-04-01 --end-date 2026-04-01 --type-id 83 --amount 1",
714
767
  [
@@ -720,6 +773,7 @@ function create(parent) {
720
773
  async (employeeId, opts) => {
721
774
  const client = getClient();
722
775
  const id = await resolveEmployeeId(client, employeeId);
776
+ const note = resolveTextOrFile(opts, "note", { required: false });
723
777
  const result = await client.timeOff.createRequest({
724
778
  employeeId: id,
725
779
  status: opts.status,
@@ -727,7 +781,7 @@ function create(parent) {
727
781
  end: opts.endDate,
728
782
  timeOffTypeId: opts.typeId,
729
783
  amount: opts.amount,
730
- notes: opts.note ? [{ from: "employee", note: opts.note }] : void 0,
784
+ notes: note ? [{ from: "employee", note }] : void 0,
731
785
  dates: opts.dates ? JSON.parse(opts.dates) : void 0
732
786
  });
733
787
  output(
@@ -738,10 +792,10 @@ function create(parent) {
738
792
  }
739
793
 
740
794
  // src/commands/timeoff/requests.ts
741
- import { Option as Option4 } from "commander";
795
+ import { Option as Option5 } from "commander";
742
796
  function requests(parent) {
743
- const cmd = parent.command("requests").description("Get time off requests (defaults to current user)").option("--request-id <id>", "Specific request ID", positiveInt).addOption(new Option4("--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(
744
- new Option4("--status <status>", "Filter by request status").choices([
797
+ 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(
798
+ new Option5("--status <status>", "Filter by request status").choices([
745
799
  "approved",
746
800
  "denied",
747
801
  "superceded",
@@ -791,25 +845,29 @@ function types(parent) {
791
845
  }
792
846
 
793
847
  // src/commands/timeoff/update-status.ts
794
- import { Option as Option5 } from "commander";
848
+ import { Option as Option6 } from "commander";
795
849
  function updateStatus(parent) {
796
850
  const cmd = parent.command("update-status <requestId>").description("Update time off request status (approve, deny, cancel)").addOption(
797
- new Option5("--status <status>", "New status").choices(["approved", "denied", "canceled"]).makeOptionMandatory()
798
- ).option("--note <text>", "Note to attach to the status change");
851
+ new Option6("--status <status>", "New status").choices(["approved", "denied", "canceled"]).makeOptionMandatory()
852
+ );
853
+ textOrFileOption(cmd, "note", { description: "Note to attach to the status change" });
799
854
  examples(cmd, [
800
855
  "7890 --status approved",
801
856
  ['7890 --status denied --note "Team at capacity that week"', "deny with note"],
802
857
  "7890 --status canceled"
803
858
  ]);
804
- cmd.action(async (requestId, opts) => {
805
- const client = getClient();
806
- const result = await client.timeOff.updateRequestStatus({
807
- requestId,
808
- status: opts.status,
809
- note: opts.note
810
- });
811
- output(result ? stripNullish(result) : { updated: true, requestId, status: opts.status });
812
- });
859
+ cmd.action(
860
+ async (requestId, opts) => {
861
+ const client = getClient();
862
+ const note = resolveTextOrFile(opts, "note", { required: false });
863
+ const result = await client.timeOff.updateRequestStatus({
864
+ requestId,
865
+ status: opts.status,
866
+ note
867
+ });
868
+ output(result ? stripNullish(result) : { updated: true, requestId, status: opts.status });
869
+ }
870
+ );
813
871
  }
814
872
 
815
873
  // src/commands/timeoff/whos-out.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bamboohr-cli",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,8 +22,8 @@
22
22
  "tsx": "^4.19.2",
23
23
  "typescript": "^5.7.2",
24
24
  "vitest": "^4.0.16",
25
- "cli-utils": "1.0.0",
26
25
  "config-eslint": "0.0.0",
26
+ "cli-utils": "1.0.0",
27
27
  "config-typescript": "0.0.0"
28
28
  },
29
29
  "engines": {