bamboohr-cli 1.0.19-g3f22a81.1 → 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 +79 -25
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -68,9 +68,57 @@ function positiveInt(raw) {
68
68
  return n;
69
69
  }
70
70
 
71
- // ../../cli-utils/dist/resolve-arg.js
71
+ // ../../cli-utils/dist/text-or-file.js
72
72
  import { readFileSync as readFileSync3 } from "fs";
73
- import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
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
+ }
74
122
 
75
123
  // ../../cli-utils/dist/builders.js
76
124
  var EXAMPLES = /* @__PURE__ */ new WeakSet();
@@ -500,10 +548,10 @@ function mergeFields(existing, extra) {
500
548
  }
501
549
 
502
550
  // src/commands/employee/goals.ts
503
- import { Option } from "commander";
551
+ import { Option as Option2 } from "commander";
504
552
  var GOAL_FILTERS = ["open", "closed", "all"];
505
553
  function goals(parent) {
506
- 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"));
507
555
  examples(cmd, ["123", ["123 --filter open", "only open goals"], ["123 --filter closed", "only closed goals"]]);
508
556
  cmd.action(async (employeeId, opts) => {
509
557
  const client = getClient();
@@ -517,10 +565,10 @@ function goals(parent) {
517
565
 
518
566
  // src/commands/employee/photo.ts
519
567
  import { writeFileSync as writeFileSync2 } from "fs";
520
- import { Option as Option2 } from "commander";
568
+ import { Option as Option3 } from "commander";
521
569
  var PHOTO_SIZES = ["original", "large", "medium", "small", "xs", "tiny"];
522
570
  function photo(parent) {
523
- 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"));
524
572
  examples(cmd, [["123 --output ./photo.jpg", "medium size (default)"], "123 --output ./photo.jpg --size large"]);
525
573
  cmd.action(async (employeeId, opts) => {
526
574
  const client = getClient();
@@ -708,11 +756,12 @@ function balance(parent) {
708
756
  }
709
757
 
710
758
  // src/commands/timeoff/create.ts
711
- import { Option as Option3 } from "commander";
759
+ import { Option as Option4 } from "commander";
712
760
  function create(parent) {
713
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(
714
- new Option3("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
715
- ).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" });
716
765
  examples(cmd, [
717
766
  "--start-date 2026-04-01 --end-date 2026-04-01 --type-id 83 --amount 1",
718
767
  [
@@ -724,6 +773,7 @@ function create(parent) {
724
773
  async (employeeId, opts) => {
725
774
  const client = getClient();
726
775
  const id = await resolveEmployeeId(client, employeeId);
776
+ const note = resolveTextOrFile(opts, "note", { required: false });
727
777
  const result = await client.timeOff.createRequest({
728
778
  employeeId: id,
729
779
  status: opts.status,
@@ -731,7 +781,7 @@ function create(parent) {
731
781
  end: opts.endDate,
732
782
  timeOffTypeId: opts.typeId,
733
783
  amount: opts.amount,
734
- notes: opts.note ? [{ from: "employee", note: opts.note }] : void 0,
784
+ notes: note ? [{ from: "employee", note }] : void 0,
735
785
  dates: opts.dates ? JSON.parse(opts.dates) : void 0
736
786
  });
737
787
  output(
@@ -742,10 +792,10 @@ function create(parent) {
742
792
  }
743
793
 
744
794
  // src/commands/timeoff/requests.ts
745
- import { Option as Option4 } from "commander";
795
+ import { Option as Option5 } from "commander";
746
796
  function requests(parent) {
747
- 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(
748
- 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([
749
799
  "approved",
750
800
  "denied",
751
801
  "superceded",
@@ -795,25 +845,29 @@ function types(parent) {
795
845
  }
796
846
 
797
847
  // src/commands/timeoff/update-status.ts
798
- import { Option as Option5 } from "commander";
848
+ import { Option as Option6 } from "commander";
799
849
  function updateStatus(parent) {
800
850
  const cmd = parent.command("update-status <requestId>").description("Update time off request status (approve, deny, cancel)").addOption(
801
- new Option5("--status <status>", "New status").choices(["approved", "denied", "canceled"]).makeOptionMandatory()
802
- ).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" });
803
854
  examples(cmd, [
804
855
  "7890 --status approved",
805
856
  ['7890 --status denied --note "Team at capacity that week"', "deny with note"],
806
857
  "7890 --status canceled"
807
858
  ]);
808
- cmd.action(async (requestId, opts) => {
809
- const client = getClient();
810
- const result = await client.timeOff.updateRequestStatus({
811
- requestId,
812
- status: opts.status,
813
- note: opts.note
814
- });
815
- output(result ? stripNullish(result) : { updated: true, requestId, status: opts.status });
816
- });
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
+ );
817
871
  }
818
872
 
819
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-g3f22a81.1",
3
+ "version": "1.0.20",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "bamboohr-client": "1.0.24-g3f22a81.1"
15
+ "bamboohr-client": "1.0.24"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "24.10.4",
@@ -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": {