bamboohr-cli 1.0.13 → 1.0.15-g3332dfd.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.
- package/README.md +91 -0
- package/dist/index.js +43 -12
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# bamboohr-cli
|
|
2
|
+
|
|
3
|
+
Command-line interface for the [BambooHR API](https://documentation.bamboohr.com/reference). 17 commands across 4 domains — employees, time off, files, and metadata.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g bamboohr-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
Set two environment variables in your shell profile:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export BAMBOO_TOKEN="your-api-token" # BambooHR > Settings > API Keys
|
|
17
|
+
export BAMBOO_COMPANY_DOMAIN="mycompany" # the subdomain in mycompany.bamboohr.com
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
All commands output JSON. Add `--pretty` to pretty-print.
|
|
23
|
+
|
|
24
|
+
### employee
|
|
25
|
+
|
|
26
|
+
| Command | Description |
|
|
27
|
+
|---------|-------------|
|
|
28
|
+
| `bamboohr employee get [id]` | Get employee by ID (defaults to current user) |
|
|
29
|
+
| `bamboohr employee search [query]` | Search employees by name, supervisor, department, location, division |
|
|
30
|
+
| `bamboohr employee directory` | Get the full company directory |
|
|
31
|
+
| `bamboohr employee photo <id>` | Download employee photo (`--size`: original, large, medium, small, xs, tiny) |
|
|
32
|
+
| `bamboohr employee goals <id>` | Get performance goals (`--status`: open, closed, all) |
|
|
33
|
+
|
|
34
|
+
### timeoff
|
|
35
|
+
|
|
36
|
+
| Command | Description |
|
|
37
|
+
|---------|-------------|
|
|
38
|
+
| `bamboohr timeoff types` | List time off types (`--requestable` to filter) |
|
|
39
|
+
| `bamboohr timeoff create [employeeId]` | Create a time off request (defaults to current user) |
|
|
40
|
+
| `bamboohr timeoff requests` | List requests (`--status`, `--start`, `--end`, `--employee`, `--type`) |
|
|
41
|
+
| `bamboohr timeoff balance [employeeId]` | Estimate time off balance (`--end` to project to future date) |
|
|
42
|
+
| `bamboohr timeoff whos-out` | View who's out today and upcoming |
|
|
43
|
+
| `bamboohr timeoff update-status <requestId>` | Approve, deny, or cancel a request |
|
|
44
|
+
|
|
45
|
+
### file
|
|
46
|
+
|
|
47
|
+
| Command | Description |
|
|
48
|
+
|---------|-------------|
|
|
49
|
+
| `bamboohr file list` | List all company files and categories |
|
|
50
|
+
| `bamboohr file get <fileId>` | Download a company file |
|
|
51
|
+
|
|
52
|
+
### meta
|
|
53
|
+
|
|
54
|
+
| Command | Description |
|
|
55
|
+
|---------|-------------|
|
|
56
|
+
| `bamboohr meta fields` | List all available BambooHR fields |
|
|
57
|
+
| `bamboohr meta departments` | List all departments |
|
|
58
|
+
| `bamboohr meta locations` | List all office locations |
|
|
59
|
+
| `bamboohr meta divisions` | List all divisions |
|
|
60
|
+
|
|
61
|
+
## Pagination
|
|
62
|
+
|
|
63
|
+
List commands accept `--limit` to control page size. Responses include a `nextPage` token — pass it back as `--offset` to fetch the next page. When `nextPage` is `null`, there are no more results.
|
|
64
|
+
|
|
65
|
+
## Examples
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Look up your own employee record
|
|
69
|
+
bamboohr employee get
|
|
70
|
+
|
|
71
|
+
# Find someone by name
|
|
72
|
+
bamboohr employee search "Jane"
|
|
73
|
+
|
|
74
|
+
# Filter by supervisor (use "me" for your direct reports)
|
|
75
|
+
bamboohr employee search --supervisor me
|
|
76
|
+
|
|
77
|
+
# Download a photo
|
|
78
|
+
bamboohr employee photo 123 --output ./photo.jpg --size large
|
|
79
|
+
|
|
80
|
+
# Check who's out this week
|
|
81
|
+
bamboohr timeoff whos-out
|
|
82
|
+
|
|
83
|
+
# Request a day off
|
|
84
|
+
bamboohr timeoff create --start 2026-04-20 --end 2026-04-20 --type-id 83 --amount 1
|
|
85
|
+
|
|
86
|
+
# See pending requests for approval
|
|
87
|
+
bamboohr timeoff requests --status requested --start 2026-01-01 --end 2026-12-31
|
|
88
|
+
|
|
89
|
+
# List available fields for custom queries
|
|
90
|
+
bamboohr meta fields
|
|
91
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5
|
+
import { dirname, join as join2 } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
4
7
|
import { styleText } from "util";
|
|
5
8
|
import { Command as Command6 } from "commander";
|
|
6
9
|
|
|
@@ -114,7 +117,7 @@ function stripResponse(obj) {
|
|
|
114
117
|
const record = obj;
|
|
115
118
|
const result = {};
|
|
116
119
|
for (const [key, value] of Object.entries(record)) {
|
|
117
|
-
if (
|
|
120
|
+
if (value === null || value === void 0) {
|
|
118
121
|
continue;
|
|
119
122
|
}
|
|
120
123
|
result[key] = stripResponse(value);
|
|
@@ -180,8 +183,16 @@ function handleError(err) {
|
|
|
180
183
|
`
|
|
181
184
|
);
|
|
182
185
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
const responseData = err?.response?.data;
|
|
187
|
+
const detail = responseData && typeof responseData === "object" ? responseData : void 0;
|
|
188
|
+
process.stderr.write(
|
|
189
|
+
`${JSON.stringify({
|
|
190
|
+
error: message,
|
|
191
|
+
...axiosStatus !== void 0 && { statusCode: axiosStatus },
|
|
192
|
+
...detail && { detail }
|
|
193
|
+
})}
|
|
194
|
+
`
|
|
195
|
+
);
|
|
185
196
|
}
|
|
186
197
|
process.exit(1);
|
|
187
198
|
}
|
|
@@ -218,10 +229,9 @@ Examples:
|
|
|
218
229
|
|
|
219
230
|
// src/commands/employee/goals.ts
|
|
220
231
|
import { Option } from "commander";
|
|
232
|
+
var GOAL_FILTERS = ["open", "closed", "all"];
|
|
221
233
|
function goals(parent) {
|
|
222
|
-
parent.command("goals <id>").description("Get employee performance goals").addOption(
|
|
223
|
-
new Option("--filter <filter>", "Filter goals by status").choices(["open", "closed", "all"]).default("all")
|
|
224
|
-
).addHelpText(
|
|
234
|
+
parent.command("goals <id>").description("Get employee performance goals").addOption(new Option("--filter <filter>", "Filter goals by status").choices(GOAL_FILTERS).default("all")).addHelpText(
|
|
225
235
|
"after",
|
|
226
236
|
`
|
|
227
237
|
Examples:
|
|
@@ -240,10 +250,9 @@ Examples:
|
|
|
240
250
|
// src/commands/employee/photo.ts
|
|
241
251
|
import { writeFileSync as writeFileSync2 } from "fs";
|
|
242
252
|
import { Option as Option2 } from "commander";
|
|
253
|
+
var PHOTO_SIZES = ["original", "large", "medium", "small", "xs", "tiny"];
|
|
243
254
|
function photo(parent) {
|
|
244
|
-
parent.command("photo <id>").description("Download employee photo").requiredOption("--output <path>", "File path to save photo").addOption(
|
|
245
|
-
new Option2("--size <size>", "Photo size").choices(["original", "large", "medium", "small", "xs", "tiny"]).default("medium")
|
|
246
|
-
).addHelpText(
|
|
255
|
+
parent.command("photo <id>").description("Download employee photo").requiredOption("--output <path>", "File path to save photo").addOption(new Option2("--size <size>", "Photo size").choices(PHOTO_SIZES).default("medium")).addHelpText(
|
|
247
256
|
"after",
|
|
248
257
|
`
|
|
249
258
|
Examples:
|
|
@@ -451,8 +460,20 @@ Examples:
|
|
|
451
460
|
|
|
452
461
|
// src/commands/timeoff/create.ts
|
|
453
462
|
import { Option as Option3 } from "commander";
|
|
463
|
+
|
|
464
|
+
// src/utils/cli.ts
|
|
465
|
+
import { InvalidArgumentError } from "commander";
|
|
466
|
+
function positiveInt(raw) {
|
|
467
|
+
const n = parseInt(raw, 10);
|
|
468
|
+
if (Number.isNaN(n) || n < 1) {
|
|
469
|
+
throw new InvalidArgumentError(`Must be a positive integer (got "${raw}")`);
|
|
470
|
+
}
|
|
471
|
+
return n;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/commands/timeoff/create.ts
|
|
454
475
|
function create(parent) {
|
|
455
|
-
parent.command("create [employeeId]").description("Create a time off request (defaults to current user)").requiredOption("--start <date>", "Start date (YYYY-MM-DD)").requiredOption("--end <date>", "End date (YYYY-MM-DD)").requiredOption("--type-id <id>", 'Time off type ID (use "timeoff types" to find IDs)',
|
|
476
|
+
parent.command("create [employeeId]").description("Create a time off request (defaults to current user)").requiredOption("--start <date>", "Start date (YYYY-MM-DD)").requiredOption("--end <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(
|
|
456
477
|
new Option3("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
|
|
457
478
|
).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`).addHelpText(
|
|
458
479
|
"after",
|
|
@@ -482,7 +503,7 @@ Examples:
|
|
|
482
503
|
// src/commands/timeoff/requests.ts
|
|
483
504
|
import { Option as Option4 } from "commander";
|
|
484
505
|
function requests(parent) {
|
|
485
|
-
parent.command("requests").description("Get time off requests (defaults to current user)").option("--id <id>", "Specific request ID",
|
|
506
|
+
parent.command("requests").description("Get time off requests (defaults to current user)").option("--id <id>", "Specific request ID", positiveInt).addOption(new Option4("--action <action>", "Access level filter").choices(["view", "approve"])).option("--employee <id>", "Filter by employee ID").option("--all", "Show all visible requests instead of just current user").option("--start <date>", "Start date (YYYY-MM-DD)").option("--end <date>", "End date (YYYY-MM-DD)").addOption(
|
|
486
507
|
new Option4("--status <status>", "Filter by request status").choices([
|
|
487
508
|
"approved",
|
|
488
509
|
"denied",
|
|
@@ -601,10 +622,20 @@ Examples:
|
|
|
601
622
|
}
|
|
602
623
|
|
|
603
624
|
// src/index.ts
|
|
625
|
+
function readPackageVersion() {
|
|
626
|
+
try {
|
|
627
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
628
|
+
const pkgPath = join2(here, "..", "package.json");
|
|
629
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
630
|
+
return pkg.version ?? "0.0.0";
|
|
631
|
+
} catch {
|
|
632
|
+
return "0.0.0";
|
|
633
|
+
}
|
|
634
|
+
}
|
|
604
635
|
var DIM = "\x1B[2m";
|
|
605
636
|
var RESET = "\x1B[0m";
|
|
606
637
|
var program = new Command6();
|
|
607
|
-
program.name("bamboohr").description("BambooHR CLI").version(
|
|
638
|
+
program.name("bamboohr").description("BambooHR CLI").version(readPackageVersion()).configureHelp({
|
|
608
639
|
styleTitle: (str) => styleText("bold", str),
|
|
609
640
|
styleUsage: (str) => styleText("dim", str),
|
|
610
641
|
styleCommandDescription: (str) => styleText("dim", str),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bamboohr-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15-g3332dfd.1",
|
|
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.
|
|
15
|
+
"bamboohr-client": "1.0.22-g3332dfd.1"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "24.10.4",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"tsx": "^4.19.2",
|
|
23
23
|
"typescript": "^5.7.2",
|
|
24
24
|
"vitest": "^4.0.16",
|
|
25
|
-
"
|
|
25
|
+
"cli-utils": "1.0.0",
|
|
26
26
|
"config-eslint": "0.0.0",
|
|
27
|
-
"
|
|
27
|
+
"config-typescript": "0.0.0"
|
|
28
28
|
},
|
|
29
29
|
"engines": {
|
|
30
30
|
"node": ">=22.0.0"
|