@go-labs-sg/bb 1.7.0 → 1.8.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.
- package/README.md +4 -2
- package/dist/commands.js +5 -0
- package/dist/index.js +24 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ The CLI talks to the production API: `https://budget-builder.getout.events`.
|
|
|
43
43
|
bb help
|
|
44
44
|
bb list-budgets
|
|
45
45
|
bb get-budget <budget-id>
|
|
46
|
-
bb update-budget-status <budget-id> <status> [--markProjectWon true]
|
|
46
|
+
bb update-budget-status <budget-id> <status> [--markProjectWon true] [--projectStatusOnCommercialRejection PITCH|LOST]
|
|
47
47
|
bb list-bills
|
|
48
48
|
bb approve-bill <bill-id>
|
|
49
49
|
bb list-approvals
|
|
@@ -54,13 +54,15 @@ Global options and flags use `--key=value` or `--key value` (see `bb help`).
|
|
|
54
54
|
|
|
55
55
|
**Authoritative command list:** run `bb help` — it includes every command, positional args, and flags. MCP exposes a subset of the same tRPC surface; the CLI additionally includes a few procedures mainly used by the web UI (e.g. `reorder-budget-items`, `update-budget-item-supplier`). You can also use MCP-style `snake_case` (e.g. `bb list_bills`); it is normalized to kebab-case.
|
|
56
56
|
|
|
57
|
+
**Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. If the parent project is `PITCH` or `LOST`, the API now marks it `WON` automatically and, when the `asana-tasks` feature flag is enabled, creates the Asana project/section/tasks automatically. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
|
|
58
|
+
|
|
57
59
|
**Mutations with `--payload`:** Commands such as `create-budget`, `create-bill`, `update-supplier`, etc. take a single JSON object (`--payload '<json>'`) matching the corresponding tRPC procedure input. Use ISO strings for date/datetime fields; the CLI coerces them where needed. The API still validates the full shape. For **`update-project`**, the project window is `dateRange.from` and `dateRange.to` (optional end); there are no separate event-date fields on the project payload. **`create-budget` / `update-budget`** do not accept `asanaTaskId`; configure the deal card on the project (`update-project` / project settings).
|
|
58
60
|
|
|
59
61
|
### Command overview
|
|
60
62
|
|
|
61
63
|
| Area | Commands (non-exhaustive) |
|
|
62
64
|
| --- | --- |
|
|
63
|
-
| **Budgets** | `list-budgets` (full payload by default; `--summary` or `--includeDetails false` for slim list), `get-budget`, `get-budget-items`, `get-budget-details`, `get-budget-categories`, `get-budget-versions`, `update-budget-status` (
|
|
65
|
+
| **Budgets** | `list-budgets` (full payload by default; `--summary` or `--includeDetails false` for slim list), `get-budget`, `get-budget-items`, `get-budget-details`, `get-budget-categories`, `get-budget-versions`, `update-budget-status` (`ESTIMATE_ACCEPTED` requires win proof, auto-marks `PITCH` or `LOST` projects `WON`, and auto-creates Asana project/section/tasks when enabled; `--projectStatusOnCommercialRejection PITCH\|LOST` is required when rejecting the only accepted/closed budget on a commercial project), `mark-budget-won` (`<budgetId>` + proof file path; `PITCH` or `LOST` projects become `WON` automatically), `create-budget` / `update-budget` (`--payload`), `delete-budget`, `create-budget-approval` (also sends approval request emails), `add-budget-items`, `update-budget-item`, `remove-budget-item`, `reorder-budget-items`, `update-budget-item-supplier`, `create-budget-category`, `update-budget-category`, `delete-budget-category`, `update-budget-commission`, `update-budget-discount` (`--payload` where noted), `upload-budget-attachment` (`<budgetId>` + local file path; uses `attachment.requestBudgetAttachmentUpload` + PUT + `attachment.confirmBudgetAttachment`) |
|
|
64
66
|
| **Bills / claims** | `list-bills` (`--isClaimable false` for bills, `--isClaimable true` for claims, omit for both), `list-claims` (claims only), `create-bill` (`--payload`; set `isClaimable=false` for a bill or `isClaimable=true` for a claim), `update-bill` (`--payload`), `delete-bill`, `create-bill-approval` (also sends approval request emails), `update-bill-status`, `patch-bill-payment` (PAID bills: `--paymentTrackingUrl`, `--paymentReference`, `--quickbooksBillId`, `--paymentDate` ISO; clear with `--clearPaymentTrackingUrl` / `--clearPaymentReference` / `--clearQuickbooksBillId` / `--clearPaymentDate` `true`), `patch-bill-invoice-number`, `get-bill-attachments`, `upload-bill-attachment` (`<billId>` + local path), `get-bill-details` |
|
|
65
67
|
| **Approvals** | `list-approvals` / `get-pending-approvals`, `approve-bill` / `reject-bill` (send reply email), `approve-budget` / `reject-budget` (send reply email), `approve-supplier` / `reject-supplier` (send reply email) |
|
|
66
68
|
| **Companies & projects** | `list-companies`, `get-company`, `create-company`, `update-company` (`--payload`), `delete-company`, `list-projects`, `get-project`, `create-project` (required: `--name`, `--companyId`, `--contactPersonId`, `--insideSalesId`, `--businessDevelopmentId`, `--venue`, `--asanaTaskId`, `--slackChannelId`, `--slackChannelUrl`, `--slackChannelName`, `--startDate` as ISO datetime for project/window start; optional `--pax`; optional `--endDate`; optional `--description`; optional `--requestQboAccountantNotification false` to skip QBO accountant emails), `update-project` (`--payload` with `dateRange.from` / `dateRange.to` for the project window; optional `requestQboAccountantNotification` in JSON), `delete-project`, `update-project-status` (`<id>` `<status>`: `PITCH` \| `WON` \| `COMPLETED` \| `LOST`; for `PITCH` → `WON` also pass `--projectManagerId` or `--projectManagerName`; when marking `WON` without an accepted/closed budget or proof, pass `--wonOverrideReason`) |
|
package/dist/commands.js
CHANGED
|
@@ -55,6 +55,9 @@ export async function updateBudgetStatus(budgetId, status, opts) {
|
|
|
55
55
|
...(opts?.markProjectWon !== undefined && {
|
|
56
56
|
markProjectWon: opts.markProjectWon,
|
|
57
57
|
}),
|
|
58
|
+
...(opts?.projectStatusOnCommercialRejection !== undefined && {
|
|
59
|
+
projectStatusOnCommercialRejection: opts.projectStatusOnCommercialRejection,
|
|
60
|
+
}),
|
|
58
61
|
});
|
|
59
62
|
out(result);
|
|
60
63
|
}
|
|
@@ -915,6 +918,7 @@ export async function listCompanies(opts) {
|
|
|
915
918
|
const result = await api.company.getCompanies.query({
|
|
916
919
|
name: opts.name,
|
|
917
920
|
createdBy: opts.createdBy,
|
|
921
|
+
active: opts.active,
|
|
918
922
|
page: opts.page ?? 1,
|
|
919
923
|
perPage: opts.perPage ?? 20,
|
|
920
924
|
});
|
|
@@ -933,6 +937,7 @@ export async function listProjects(opts) {
|
|
|
933
937
|
companyId: opts.companyId,
|
|
934
938
|
name: opts.name,
|
|
935
939
|
status: opts.status,
|
|
940
|
+
active: opts.active,
|
|
936
941
|
page: opts.page ?? 1,
|
|
937
942
|
perPage: opts.perPage ?? 20,
|
|
938
943
|
});
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,19 @@ function parseOptionalBoolFlag(flags, key) {
|
|
|
26
26
|
return false;
|
|
27
27
|
throw new Error(`--${key} must be true or false.`);
|
|
28
28
|
}
|
|
29
|
+
function parseCommercialRejectionProjectStatus(flags) {
|
|
30
|
+
const raw = flags.projectStatusOnCommercialRejection;
|
|
31
|
+
if (raw === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
if (raw === true) {
|
|
34
|
+
throw new Error("--projectStatusOnCommercialRejection requires PITCH or LOST.");
|
|
35
|
+
}
|
|
36
|
+
const status = String(raw).toUpperCase();
|
|
37
|
+
if (status === "PITCH" || status === "LOST") {
|
|
38
|
+
return status;
|
|
39
|
+
}
|
|
40
|
+
throw new Error("--projectStatusOnCommercialRejection must be PITCH or LOST.");
|
|
41
|
+
}
|
|
29
42
|
function parseListBillsFlags(flags) {
|
|
30
43
|
const statusRaw = getFlag(flags, "status");
|
|
31
44
|
const createdByIdsRaw = getFlag(flags, "createdByIds");
|
|
@@ -113,9 +126,11 @@ Budgets
|
|
|
113
126
|
get-budget-details <id> Full detail (margins, suppliers, etc.)
|
|
114
127
|
get-budget-categories
|
|
115
128
|
get-budget-versions <budgetId>
|
|
116
|
-
update-budget-status <id> <status> [--markProjectWon true|false]
|
|
129
|
+
update-budget-status <id> <status> [--markProjectWon true|false] [--projectStatusOnCommercialRejection PITCH|LOST]
|
|
130
|
+
ESTIMATE_ACCEPTED requires win proof, auto-marks PITCH or LOST projects WON, and auto-creates the Asana project/section when enabled.
|
|
131
|
+
ESTIMATE_REJECTED requires --projectStatusOnCommercialRejection when rejecting the only accepted/closed budget on a commercial project.
|
|
117
132
|
status: ${budgetStatusesForHelp.join(", ")}
|
|
118
|
-
mark-budget-won <budgetId> <filePath> [--markProjectWon true|false] Upload signed quote/PO proof and set status to ESTIMATE_ACCEPTED
|
|
133
|
+
mark-budget-won <budgetId> <filePath> [--markProjectWon true|false] Upload signed quote/PO proof and set status to ESTIMATE_ACCEPTED; PITCH or LOST projects become WON automatically
|
|
119
134
|
create-budget --payload '<json>' (budget.createBudget; Asana deal card is on the project)
|
|
120
135
|
update-budget --payload '<json>' (budget.updateBudget; must include id)
|
|
121
136
|
delete-budget <budgetId>
|
|
@@ -160,12 +175,14 @@ Approvals
|
|
|
160
175
|
reject-supplier <supplierId> --reason <text> (also sends requester reply email)
|
|
161
176
|
|
|
162
177
|
Companies & projects
|
|
163
|
-
list-companies [--name] [--createdBy] [--page] [--perPage]
|
|
178
|
+
list-companies [--name] [--createdBy] [--active true|false] [--page] [--perPage]
|
|
179
|
+
Omit --active to include both active and inactive companies.
|
|
164
180
|
get-company <id>
|
|
165
181
|
create-company --name --website <url>
|
|
166
182
|
update-company --payload '<json>' (company.updateCompany; must include id, name, website)
|
|
167
183
|
delete-company <id>
|
|
168
|
-
list-projects [--companyId] [--name] [--status] [--page] [--perPage]
|
|
184
|
+
list-projects [--companyId] [--name] [--status] [--active true|false] [--page] [--perPage]
|
|
185
|
+
Omit --active to include both active and inactive projects.
|
|
169
186
|
get-project <id>
|
|
170
187
|
create-project --name --companyId --contactPersonId --insideSalesId --businessDevelopmentId --venue --asanaTaskId --slackChannelId --slackChannelUrl --slackChannelName --startDate <ISO> [--pax] [--endDate <ISO>] [--description] [--requestQboAccountantNotification false]
|
|
171
188
|
update-project --payload '<json>' (project.updateProject; optional requestQboAccountantNotification; default notify like web)
|
|
@@ -339,6 +356,7 @@ async function main() {
|
|
|
339
356
|
}
|
|
340
357
|
await updateBudgetStatus(id, status, {
|
|
341
358
|
markProjectWon: parseOptionalBoolFlag(flags, "markProjectWon"),
|
|
359
|
+
projectStatusOnCommercialRejection: parseCommercialRejectionProjectStatus(flags),
|
|
342
360
|
});
|
|
343
361
|
break;
|
|
344
362
|
}
|
|
@@ -723,6 +741,7 @@ async function main() {
|
|
|
723
741
|
await listCompanies({
|
|
724
742
|
name: getFlag(flags, "name"),
|
|
725
743
|
createdBy: getFlag(flags, "createdBy"),
|
|
744
|
+
active: parseOptionalBoolFlag(flags, "active"),
|
|
726
745
|
page: parsePositiveIntFlag(getFlag(flags, "page"), "--page"),
|
|
727
746
|
perPage: parsePositiveIntFlag(getFlag(flags, "perPage"), "--perPage"),
|
|
728
747
|
});
|
|
@@ -766,6 +785,7 @@ async function main() {
|
|
|
766
785
|
companyId: getFlag(flags, "companyId"),
|
|
767
786
|
name: getFlag(flags, "name"),
|
|
768
787
|
status: parseOptionalExtendedProjectStatus(statusRaw !== undefined ? String(statusRaw) : undefined),
|
|
788
|
+
active: parseOptionalBoolFlag(flags, "active"),
|
|
769
789
|
page: parsePositiveIntFlag(getFlag(flags, "page"), "--page"),
|
|
770
790
|
perPage: parsePositiveIntFlag(getFlag(flags, "perPage"), "--perPage"),
|
|
771
791
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/bb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Budget Builder CLI for AI agents — manage budgets, bills, and claims; bill records use isClaimable=false for bills and isClaimable=true for claims.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|