@go-labs-sg/bb 1.7.0 → 1.9.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 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` (`--markProjectWon true` can move the parent project to `WON` for accepted/closed estimates), `mark-budget-won` (`<budgetId>` + proof file path; optional `--markProjectWon true`), `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`) |
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.7.0",
3
+ "version": "1.9.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",