@go-labs-sg/bb 2.15.0 → 2.17.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 +10 -3
- package/command-manifest.json +71 -1
- package/command-reference.md +9 -1
- package/dist/commands.js +22 -6
- package/dist/index.js +32 -9
- package/dist/parse-cli-enums.js +30 -0
- package/dist/registry/index.js +22 -2
- package/package.json +1 -1
- package/role-aware-agent-guide.md +2 -0
package/README.md
CHANGED
|
@@ -183,6 +183,10 @@ external provider.
|
|
|
183
183
|
|
|
184
184
|
### Mutation safety
|
|
185
185
|
|
|
186
|
+
While an estimate email is `QUEUED`, `PROCESSING`, or awaiting provider
|
|
187
|
+
reconciliation, the API makes that Budget read-only. Budget-changing CLI
|
|
188
|
+
commands return a conflict until delivery becomes `SENT` or `FAILED`.
|
|
189
|
+
|
|
186
190
|
Every canonical command is classified by effect: `state-change`, `email`, `external-write`, `delete`, and/or `financial-write`. Interactive runs require one exact `CONFIRM`. Non-interactive runs require the corresponding flags (`--allow-state-change`, `--allow-email`, `--allow-external-write`, `--allow-delete`, and `--allow-financial-write`); commands with multiple effects require every matching flag. Agents must still get user confirmation in chat first—the runtime gate is not user authorization.
|
|
187
191
|
|
|
188
192
|
**Approval email exclusions:** Approval requests create pending database records for every eligible approver, including configured non-recipient admin accounts. Automated approval-request emails skip those accounts.
|
|
@@ -191,7 +195,7 @@ Every canonical command is classified by effect: `state-change`, `email`, `exter
|
|
|
191
195
|
|
|
192
196
|
**Mutations with `--payload`:** Commands such as `bb budget create`, `bb bill create`, and `bb supplier update` 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. Plain `description` fields for item create/update are converted to `descriptionRichText`; pass `descriptionRichText` directly when formatted Tiptap JSON is required. For **`bb project update`**, the project window is `dateRange.from` and `dateRange.to` (optional end); there are no separate event-date fields on the project payload. **`bb budget create` / `bb budget update`** do not accept `asanaTaskId`; configure the deal card on the project (`bb project update` / project settings).
|
|
193
197
|
|
|
194
|
-
**Contact-person estimate email:** `bb budget estimate send --payload '<json>'` calls the same `email.sendEstimateToContactPerson` procedure as the web composer. The payload requires `budgetId`, `estimateId`, optional `estimateDocNumber`, `to`, `cc`, `replyTo`, `subject`, HTML `content`, and HTML `signature`. It
|
|
198
|
+
**Contact-person estimate email:** `bb budget estimate send --payload '<json>'` calls the same `email.sendEstimateToContactPerson` procedure as the web composer. The payload requires `budgetId`, `estimateId`, optional `estimateDocNumber`, `to`, `cc`, `replyTo`, `subject`, HTML `content`, and HTML `signature`. It durably queues worker delivery of the QuickBooks PDF, standard terms, and Budget Builder budget attachments, and returns the outbound-email and operation IDs immediately. Worker retries reuse one provider idempotency key; the budget becomes `ESTIMATE_SENT` only after Resend accepts the email. The command requires interactive `CONFIRM`; inspect the budget, recipients, and HTML first.
|
|
195
199
|
|
|
196
200
|
**Customer-invoice workflow parity:** `bb customer-invoice list` uses the same global/project list procedure and metrics as the web pages; omit filters for the global list or use `--projectId` for project scope. `bb customer-invoice send` uses the same protected email workflow as the web composer and marks a successful invoice `SENT`. `bb customer-invoice approve` and `bb customer-invoice reject` are Admin-only batch operations: callers select a batch ID, and the API resolves its internal pending Admin approval record. `bb customer-invoice sync` follows QuickBooks' paid state and zero balance, restoring `SENT` or `APPROVED` if that payment is reversed. Invoice approval refuses voided invoices and closes the estimate only when approved invoice coverage totals 100%; deletion, voiding, rejection, expiry, and QBO synchronization use the same estimate-reopening and live-payment guards as the web app.
|
|
197
201
|
|
|
@@ -207,11 +211,14 @@ For agent-driven invoice work, use this read-before-write sequence:
|
|
|
207
211
|
Project Hub setup and commercial-document reconciliation are durable, asynchronous Budget Builder operations. Read status before requesting either mutation:
|
|
208
212
|
|
|
209
213
|
```bash
|
|
214
|
+
bb project hub list --q <project-or-company> --status WON,COMPLETED
|
|
210
215
|
bb project hub status <project-id>
|
|
211
216
|
bb project hub setup <project-id>
|
|
212
217
|
bb project hub sync <project-id>
|
|
213
218
|
```
|
|
214
219
|
|
|
220
|
+
`list` is read-only and returns active projects with a Project Hub integration, including setup state and the stored Hub URL when available. It supports project/company search, project-status filters, pagination, and sorting.
|
|
221
|
+
|
|
215
222
|
`status` reports eligibility, whether setup can be requested, the current setup status, the latest setup error, and the client Hub URL. `setup` uses the same eligibility and accepted-estimate checks as the web button and may create the operational Asana project before provisioning Drive and Project Hub. `sync` requires an existing `READY` native-layout integration and queues a complete reconciliation of accepted estimates, commercial attachments, win proofs, and eligible customer invoices into Asana and Drive.
|
|
216
223
|
|
|
217
224
|
Both mutation commands write external state asynchronously and therefore require `state-change` and `external-write` confirmation. In non-interactive use, pass both `--allow-state-change` and `--allow-external-write` only after obtaining explicit user approval. A successful `queued` response means the durable operation was accepted. `status` tracks setup readiness; the sync response returns its outbox operation ID, which an Admin can inspect with the integration-operation commands when completion or failure diagnostics are required.
|
|
@@ -229,14 +236,14 @@ Project and budget query payloads keep the Asana identities explicit: `asanaTask
|
|
|
229
236
|
| **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`, `rename-budget-version`, `restore-budget-version`, `update-budget-status` (`ESTIMATE_ACCEPTED` requires win proof, auto-marks `PITCH` or `LOST` projects `WON`, and auto-creates an Asana Event Ops section from Prompt 5 tasks when enabled; Prompt 5 skips quantity-zero items, combines matching non-GO-internal suppliers, keeps each GO internal item separate, removes generated work that repeats another line item or group, and schedules applicable subtasks relative to the project start date; `--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), `create-estimate`, `send-estimate-to-contact-person` (same contact-person email workflow as web), `add-budget-items`, `update-budget-item`, `remove-budget-item`, `reorder-budget-items`, `update-budget-item-supplier`, `mark-budget-items-not-utilized`, `restore-budget-item`, `create-placeholder-bill` (admin recovery), `create-budget-category`, `update-budget-category`, `delete-budget-category`, `update-budget-commission`, `delete-budget-commission`, `update-budget-discount`, `delete-budget-discount` (`--payload` where noted), `upload-budget-attachment` (`<budgetId>` + local file path; uses `attachment.requestBudgetAttachmentUpload` + PUT + `attachment.confirmBudgetAttachment`) |
|
|
230
237
|
| **Bills / claims** | `list-bills` (`--isClaimable false` for bills, `--isClaimable true` for claims, omit for both), `list-claims` (claims only), `validate-bill-selection` (`--payload`; runs the same supplier, line-item, and quotation-coverage checks as the web flow; `alreadyPaid` never bypasses them), `stage-bill-attachment` (securely uploads invoice/payment-proof files before creation and returns attachment JSON; ownership and one-hour expiry are enforced by a server-side staged-upload record rather than encoded in the object key), `cleanup-staged-bill-attachments`, `create-bill` (`--payload`; set `isClaimable=false` for a bill, `isClaimable=true` for a claim; supplier bills require positive `extractedAmount` and `amount`, with `amount <= extractedAmount`; an already-paid supplier bill sets `alreadyPaid=true` and requires `paymentReference` plus a staged PDF in `paymentProofAttachments`; admin creation automatically queues QBO finalization while other roles remain pending approval; non-legacy supplier bills from 1 Jul 2026 00:00 SGT require approved quotation coverage even when already paid), `update-bill` (`--payload`), `update-bill-payment-evidence` (`--payload`; replaces the payment reference and payment-proof PDFs for an already-paid bill), `delete-bill`, `create-bill-approval` (also sends approval request emails), `update-bill-status` (`PAID` requires `--paymentReference`; pass `--paymentProof <receipt.pdf>` to stage and submit a PDF up to 20MB atomically, or omit it only when BB already has payment proof; moving to `PAID` runs the server's paid-bill notification workflow), `patch-bill-payment` (PAID bills: `--paymentTrackingUrl`, `--paymentReference`, `--quickbooksBillId`, `--paymentDate` ISO; clearing a paid bill's QuickBooks link is not allowed), `patch-bill-invoice-number`, `get-bill-attachments`, `upload-bill-attachment` (`<billId>` + local path), `get-bill-details` |
|
|
231
238
|
| **Quotations** | `list-quotations` (supports project, budget, supplier, status, requester, and text-search filters), `get-quotation`, `upload-quotation-attachment` (`<projectId>` + PDF/JPEG/PNG path up to 20MB; returns attachment JSON for payload use), `cleanup-staged-quotation-attachments`, `create-quotation` (`--payload` for `quotation.createDraft`; include `amountWithoutGst` and `gstAmount`), `update-quotation` (`--payload`; updates a `DRAFT` or `REJECTED` quotation), `delete-quotation`, `submit-quotation`, `approve-quotation`, `reject-quotation`, `download-quotation-pdf` (`original`, `staff`, or `final`) |
|
|
232
|
-
| **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `list-customer-invoices` (global/project/budget filters plus summary metrics), `get-customer-invoice`, `get-customer-invoice-email-context`, `create-customer-invoice`, `discard-customer-invoice`, `delete-customer-invoice`, `void-customer-invoice`, `approve-customer-invoice` (admin), `reject-customer-invoice` (admin), `send-customer-invoice-to-contact-person`, `download-customer-invoice-pdf
|
|
239
|
+
| **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `list-customer-invoices` (global/project/budget filters plus summary metrics), `get-customer-invoice`, `get-customer-invoice-email-context`, `create-customer-invoice`, `discard-customer-invoice`, `delete-customer-invoice`, `void-customer-invoice`, `approve-customer-invoice` (admin), `reject-customer-invoice` (admin), `send-customer-invoice-to-contact-person`, `download-customer-invoice-pdf` (non-admins cannot download while approval is pending), `sync-customer-invoice` |
|
|
233
240
|
| **Approvals** | `list-approvals` / `get-pending-approvals` (`--type budget\|supplier\|bill\|quotation\|customer_invoice\|all`), `approve-bill` / `reject-bill` (send reply email), `approve-budget` / `reject-budget` (send reply email), `approve-supplier` / `reject-supplier` (send reply email), `approve-quotation` / `reject-quotation`, `approve-customer-invoice` / `reject-customer-invoice` |
|
|
234
241
|
| **Companies & projects** | `list-companies`, `get-company`, `create-company`, `update-company` (`--payload`), `delete-company`, `list-projects`, `get-project` (its budget overview returns `totalRevenue`, calculated only from Estimate Accepted and Estimate Closed budgets), `get-project-hub-status`, `setup-project-hub`, `sync-project-hub-commercial-documents`, `create-project` (required: `--name`, `--companyId`, `--contactPersonId`, `--insideSalesId`, `--businessDevelopmentId`, `--venue`, `--startDate` as ISO datetime for project/window start; when `--asanaTaskId` is omitted, the CLI searches open Asana lead tasks in the Deals project, prompts for one of the top five matches, and resolves Slack channel fields from the selected deal card; optional `--asanaSearch`, `--pax`, `--endDate`, `--description`, `--projectManagerId`; always requests QBO project import like the web app), `update-project` (`--payload` with `dateRange.from` / `dateRange.to` for the project window; optional `projectManagerId` and `requestQboAccountantNotification` in JSON), `delete-project`, `check-project-reconciliation <id>` (runs the web app's live checks without changing status), `reconcile-project <id>` (reruns checks transactionally and marks an eligible project `RECONCILED`), `complete-project <id>` (reruns validation, marks a reconciled project `COMPLETED`, and queues QuickBooks placeholder cleanup), `import-qbo-project`, `update-project-status` (`<id>` `<status>`: `PITCH` \| `WON` \| `COMPLETED` \| `RECONCILED` \| `LOST`; close-out follows `WON` → `RECONCILED` → `COMPLETED`, and reconciliation requires every accepted/closed budget line to have an Approved/Paid bill or claim or be explicitly Not Utilized; marking `COMPLETED` queues deletion of every remaining project placeholder bill from QuickBooks; for `PITCH` → `WON` also pass a Budget Builder user `--projectManagerId` or `--projectManagerEmail`; when marking `WON` without an accepted/closed budget or proof, pass `--wonOverrideReason`) |
|
|
235
242
|
| **Contacts** | `list-contacts`, `create-contact-person` (`--payload`), `update-contact-person` (`--payload`) |
|
|
236
243
|
| **Suppliers & items** | `list-suppliers` (defaults to active suppliers, `--perPage 10`, sorted by `createdAt` desc; supports `--name`, `--sortBy` for scalar supplier fields, `--sortDir`, `--createdBy`, `--gstRegistered`, `--status`, `--supplierTags`, `--active false` for archived suppliers), `create-supplier` (`--payload`; when supplier status is `PENDING_APPROVAL`, also runs `supplier.createSupplierApproval` and `email.sendSupplierApprovalRequestEmail`), `update-supplier` (`--payload`; when supplier status is `PENDING_APPROVAL`, also runs `supplier.createSupplierApproval` and `email.sendSupplierApprovalRequestEmail`), `delete-suppliers` (`--ids` CSV; admin; archives/deactivates related items), `reactivate-suppliers` (`--ids` CSV; admin; reactivates related items), `create-certification` / `create-payment-method` / `create-supplier-role` / `create-supplier-tag` (`--name`), `get-supplier-details` (includes `supplierApprovalSummary` for pending approvers, superseded approvers, and the actual responder/respondedAt metadata), `get-supplier-analytics` (admin), `list-items`, `create-item` (`--payload`), `update-item` (`--payload`), `archive-items` (`--ids` CSV, max 100; Budget Builder only; users can archive their own items, leads/admins any item; blocked by Draft/Pending Approval/Approved budgets), `delete-item` (admin; archives in Budget Builder and makes the item inactive in QuickBooks), `get-item`, `list-item-categories`, `create-item-category` / `update-item-category` / `delete-item-categories` (admin; `--ids` CSV for delete) |
|
|
237
244
|
| **Dashboard & users** | `whoami` (current API-key owner identity and role), `list-users`, `create-user` (admin; provisions an API-only service identity with no Google sign-in; `--email`, optional `--name`, optional `--role` defaulting to `USER`), `create-api-key` (`--name`; defaults to the caller; admin-only `--userId` for another user; raw key shown once), `list-api-keys` (defaults to the caller; admin-only `--userId` for another user), `revoke-api-key` (key ID; admin-only `--userId` for another user), `get-user-performance`, `get-dashboard`, `get-monthly-metrics`, `get-system-overview`, `get-estimate-performance`, `get-financial-overview` (performance/dashboard commands are admin-only) |
|
|
238
245
|
| **Errors (admin)** | `get-recent-errors`, `get-error-metrics` |
|
|
239
|
-
| **Automation (admin)** | `list-integration-operations`, `retry-integration-operation` |
|
|
246
|
+
| **Automation (admin)** | `list-integration-operations`, `retry-integration-operation` (Resend resolution requires `--confirmExternalStateReconciled true` plus `--outboundEmailResolution ACCEPTED\|NOT_ACCEPTED_RETRY`; include `--providerMessageId` when accepted) |
|
|
240
247
|
| **Historical / benchmarks** | `get-approved-budgets`, `get-budget-category-benchmarks`, `get-item-pricing-history`, `get-supplier-pricing-history` |
|
|
241
248
|
|
|
242
249
|
The CLI intentionally wraps low-level upload-request/confirm procedures into file-based commands and omits browser-only helpers such as navigation counts, combobox/facet data, recent-page bookkeeping, and live UI subscriptions. Operational workflows for bills, claims, quotations, customer invoices, project reconciliation/completion, and integration recovery are available directly.
|
package/command-manifest.json
CHANGED
|
@@ -3452,7 +3452,7 @@
|
|
|
3452
3452
|
"download-customer-invoice-pdf",
|
|
3453
3453
|
"download_customer_invoice_pdf"
|
|
3454
3454
|
],
|
|
3455
|
-
"summary": "Download
|
|
3455
|
+
"summary": "Download a customer invoice PDF when permitted.",
|
|
3456
3456
|
"globalOptions": [
|
|
3457
3457
|
{
|
|
3458
3458
|
"name": "--help",
|
|
@@ -4190,6 +4190,76 @@
|
|
|
4190
4190
|
"effects": [],
|
|
4191
4191
|
"legacyTarget": "list-projects"
|
|
4192
4192
|
},
|
|
4193
|
+
{
|
|
4194
|
+
"path": ["project", "hub", "list"],
|
|
4195
|
+
"legacyAliases": ["list-project-hubs", "list_project_hubs"],
|
|
4196
|
+
"summary": "List project hubs.",
|
|
4197
|
+
"globalOptions": [
|
|
4198
|
+
{
|
|
4199
|
+
"name": "--help",
|
|
4200
|
+
"description": "Show help for this command."
|
|
4201
|
+
},
|
|
4202
|
+
{
|
|
4203
|
+
"name": "--quiet",
|
|
4204
|
+
"description": "Suppress non-error diagnostics."
|
|
4205
|
+
},
|
|
4206
|
+
{
|
|
4207
|
+
"name": "--debug",
|
|
4208
|
+
"description": "Emit sanitized diagnostic traces."
|
|
4209
|
+
},
|
|
4210
|
+
{
|
|
4211
|
+
"name": "--api-url",
|
|
4212
|
+
"description": "Override the Budget Builder API base URL."
|
|
4213
|
+
},
|
|
4214
|
+
{
|
|
4215
|
+
"name": "--allow-state-change",
|
|
4216
|
+
"description": "Allow a Budget Builder state change in non-interactive use."
|
|
4217
|
+
},
|
|
4218
|
+
{
|
|
4219
|
+
"name": "--allow-email",
|
|
4220
|
+
"description": "Allow sending email in non-interactive use."
|
|
4221
|
+
},
|
|
4222
|
+
{
|
|
4223
|
+
"name": "--allow-external-write",
|
|
4224
|
+
"description": "Allow writes to external systems in non-interactive use."
|
|
4225
|
+
},
|
|
4226
|
+
{
|
|
4227
|
+
"name": "--allow-delete",
|
|
4228
|
+
"description": "Allow deleting data in non-interactive use."
|
|
4229
|
+
},
|
|
4230
|
+
{
|
|
4231
|
+
"name": "--allow-financial-write",
|
|
4232
|
+
"description": "Allow financial-record changes in non-interactive use."
|
|
4233
|
+
},
|
|
4234
|
+
{
|
|
4235
|
+
"name": "--q",
|
|
4236
|
+
"description": "Search project and company names."
|
|
4237
|
+
},
|
|
4238
|
+
{
|
|
4239
|
+
"name": "--status",
|
|
4240
|
+
"description": "Filter by comma-separated project statuses."
|
|
4241
|
+
},
|
|
4242
|
+
{
|
|
4243
|
+
"name": "--page",
|
|
4244
|
+
"description": "Select a results page."
|
|
4245
|
+
},
|
|
4246
|
+
{
|
|
4247
|
+
"name": "--perPage",
|
|
4248
|
+
"description": "Set the results page size."
|
|
4249
|
+
},
|
|
4250
|
+
{
|
|
4251
|
+
"name": "--sortBy",
|
|
4252
|
+
"description": "Sort by startDate, name, companyName, or status."
|
|
4253
|
+
},
|
|
4254
|
+
{
|
|
4255
|
+
"name": "--sortDir",
|
|
4256
|
+
"description": "Sort in asc or desc order."
|
|
4257
|
+
}
|
|
4258
|
+
],
|
|
4259
|
+
"argumentMode": "legacy-passthrough",
|
|
4260
|
+
"effects": [],
|
|
4261
|
+
"legacyTarget": "list-project-hubs"
|
|
4262
|
+
},
|
|
4193
4263
|
{
|
|
4194
4264
|
"path": ["project", "get"],
|
|
4195
4265
|
"legacyAliases": ["get-project", "get_project"],
|
package/command-reference.md
CHANGED
|
@@ -610,7 +610,7 @@ Effects: state-change, email.
|
|
|
610
610
|
|
|
611
611
|
## `bb customer-invoice pdf download`
|
|
612
612
|
|
|
613
|
-
Download
|
|
613
|
+
Download a customer invoice PDF when permitted.
|
|
614
614
|
|
|
615
615
|
Legacy aliases: `download-customer-invoice-pdf`, `download_customer_invoice_pdf`.
|
|
616
616
|
|
|
@@ -736,6 +736,14 @@ Legacy aliases: `list-projects`, `list_projects`.
|
|
|
736
736
|
|
|
737
737
|
Effects: none.
|
|
738
738
|
|
|
739
|
+
## `bb project hub list`
|
|
740
|
+
|
|
741
|
+
List project hubs.
|
|
742
|
+
|
|
743
|
+
Legacy aliases: `list-project-hubs`, `list_project_hubs`.
|
|
744
|
+
|
|
745
|
+
Effects: none.
|
|
746
|
+
|
|
739
747
|
## `bb project get`
|
|
740
748
|
|
|
741
749
|
Get project.
|
package/dist/commands.js
CHANGED
|
@@ -1091,7 +1091,7 @@ export async function createEstimate(budgetId, preflight) {
|
|
|
1091
1091
|
const result = await api.quickbooks.createEstimate.mutate({ budgetId });
|
|
1092
1092
|
out(result);
|
|
1093
1093
|
}
|
|
1094
|
-
export const describeEstimateEmailConfirmation = (input) => `to ${input.to}; CC ${input.cc.length > 0 ? input.cc.join(", ") : "none"}; reply-to ${input.replyTo}; subject "${input.subject}";
|
|
1094
|
+
export const describeEstimateEmailConfirmation = (input) => `to ${input.to}; CC ${input.cc.length > 0 ? input.cc.join(", ") : "none"}; reply-to ${input.replyTo}; subject "${input.subject}"; queue durable worker delivery with the QBO estimate PDF, terms and conditions, and Budget Builder attachments; mark the estimate sent after provider acceptance`;
|
|
1095
1095
|
export const sendEstimateToContactPersonFromPayload = async (raw) => {
|
|
1096
1096
|
const input = parseSendEstimateToContactPersonPayload(raw);
|
|
1097
1097
|
await assertSensitiveWorkflowConfirmed({
|
|
@@ -1907,6 +1907,14 @@ export async function listProjects(opts) {
|
|
|
1907
1907
|
});
|
|
1908
1908
|
out(result);
|
|
1909
1909
|
}
|
|
1910
|
+
export const listProjectHubs = async (opts) => {
|
|
1911
|
+
const result = await api.project.getAllProjectHubs.query({
|
|
1912
|
+
...opts,
|
|
1913
|
+
page: opts.page ?? 1,
|
|
1914
|
+
perPage: opts.perPage ?? 20,
|
|
1915
|
+
});
|
|
1916
|
+
out(result);
|
|
1917
|
+
};
|
|
1910
1918
|
export async function getProject(id) {
|
|
1911
1919
|
const [project, budgetsOverview, billsOverview] = await Promise.all([
|
|
1912
1920
|
api.project.getProjectDetailsById.query({ id }),
|
|
@@ -2015,17 +2023,25 @@ export const listIntegrationOperations = async (input) => {
|
|
|
2015
2023
|
const result = await api.integration.listOperations.query(input);
|
|
2016
2024
|
out(result);
|
|
2017
2025
|
};
|
|
2018
|
-
export const retryIntegrationOperation = async (operationId, confirmExternalStateReconciled) => {
|
|
2026
|
+
export const retryIntegrationOperation = async (operationId, confirmExternalStateReconciled, outboundEmailResolution, providerMessageId) => {
|
|
2019
2027
|
await assertSensitiveWorkflowConfirmed({
|
|
2020
|
-
action:
|
|
2028
|
+
action: outboundEmailResolution === "ACCEPTED"
|
|
2029
|
+
? "Reconcile integration operation as completed"
|
|
2030
|
+
: "Retry integration operation",
|
|
2021
2031
|
entity: `operation ${operationId}`,
|
|
2022
|
-
details:
|
|
2023
|
-
?
|
|
2024
|
-
:
|
|
2032
|
+
details: outboundEmailResolution === "ACCEPTED"
|
|
2033
|
+
? `mark provider-accepted email sent with message ID ${providerMessageId ?? "<missing>"}`
|
|
2034
|
+
: outboundEmailResolution === "NOT_ACCEPTED_RETRY"
|
|
2035
|
+
? "rotate the Resend idempotency key and retry provider delivery"
|
|
2036
|
+
: confirmExternalStateReconciled
|
|
2037
|
+
? "after confirming the external state has been reconciled"
|
|
2038
|
+
: undefined,
|
|
2025
2039
|
});
|
|
2026
2040
|
const result = await api.integration.retryOperation.mutate({
|
|
2027
2041
|
operationId,
|
|
2028
2042
|
confirmExternalStateReconciled,
|
|
2043
|
+
outboundEmailResolution,
|
|
2044
|
+
providerMessageId,
|
|
2029
2045
|
});
|
|
2030
2046
|
out(result);
|
|
2031
2047
|
};
|
package/dist/index.js
CHANGED
|
@@ -5,9 +5,9 @@ import { resolve } from "node:path";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { BUDGET_BUILDER_API_BASE_URL, configureBudgetBuilderApiBaseUrl, DEFAULT_BUDGET_BUILDER_API_BASE_URL, requireApiKey, } from "./api-client.js";
|
|
7
7
|
import { consumeCliQuietFlags, logCliAction, sanitizeFlagsForTrace, setCliQuiet, shouldLogCliActions, } from "./cli-trace.js";
|
|
8
|
-
import { addBudgetItems, approveBill, approveBudget, approveCustomerInvoice, approveQuotation, approveSupplier, archiveItemsByIds, checkCustomerInvoiceReadiness, checkProjectReconciliation, cleanupStagedBillAttachments, cleanupStagedQuotationAttachments, completeProject, createApiKeyForUser, createBillApproval, createBillFromPayload, createBudgetApproval, createBudgetCategory, createBudgetFromPayload, createCompany, createContactPersonFromPayload, createCustomerInvoice, createEstimate, createInboundSource, createItemCategory, createItemFromPayload, createPlaceholderBillForBudgetItem, createProject, createQuotationFromPayload, createSupplierCertification, createSupplierFromPayload, createSupplierPaymentMethod, createSupplierRoleOption, createSupplierTagOption, createUser, deleteBillById, deleteBudgetById, deleteBudgetCategory, deleteBudgetCommission, deleteBudgetDiscount, deleteCompanyById, deleteCustomerInvoice, deleteItemById, deleteItemCategoriesByIds, deleteProjectById, deleteQuotationById, deleteSuppliersByIds, discardCreatingCustomerInvoice, downloadCustomerInvoicePdf, downloadQuotationPdf, getApprovedBudgets, getBillAttachments, getBillDetails, getBudget, getBudgetCategories, getBudgetCategoryBenchmarks, getBudgetDetails, getBudgetItemsOnly, getBudgetVersions, getCompany, getCustomerInvoice, getCustomerInvoiceEmailContext, getDashboard, getErrorMetrics, getEstimatePerformance, getFinancialOverview, getInboundSource, getInboundSubmission, getItem, getItemPricingHistory, getMonthlyMetrics, getProject, getProjectHubStatus, getQuotationDetails, getRecentErrors, getSupplierAnalytics, getSupplierDetails, getSupplierPricingHistory, getSystemOverview, getUserPerformance, importQuickBooksProjectId, listApiKeysForUser, listApprovals, listBills, listBudgets, listCompanies, listContacts, listCustomerInvoices, listEligibleCustomerInvoiceBudgets, listInboundSources, listInboundSubmissions, listIntegrationOperations, listItemCategories, listItems, listProjects, listQuotations, listSuppliers, listUsers, markBudgetWonWithProof, patchBillInvoiceNumber, patchBillPayment, reactivateSuppliersByIds, reconcileProject, rejectBill, rejectBudget, rejectCustomerInvoice, rejectQuotation, rejectSupplier, removeBudgetItem, renameBudgetVersion, reorderBudgetItemsCli, restoreBudgetVersion, retryIntegrationOperation, revokeApiKeyForUser, saveInboundAutomationConfig, saveInboundMappingVersion, sendCustomerInvoiceToContactPersonFromPayload, sendEstimateToContactPersonFromPayload, setBudgetItemsNotUtilized, setupProjectHub, stageBillAttachmentsFromPaths, submitQuotation, syncCustomerInvoice, syncProjectHubCommercialDocuments, updateBillFromPayload, updateBillPaymentEvidenceFromPayload, updateBillStatus, updateBudgetCategory, updateBudgetCommissionFromPayload, updateBudgetDiscountFromPayload, updateBudgetFromPayload, updateBudgetItem, updateBudgetItemSupplierCli, updateBudgetStatus, updateCompanyFromPayload, updateContactPersonFromPayload, updateInboundProcessing, updateInboundSource, updateItemCategory, updateItemFromPayload, updateProjectFromPayload, updateProjectStatus, updateQuotationFromPayload, updateSupplierFromPayload, uploadBillAttachmentFromPath, uploadBillAttachmentsFromPaths, uploadBillDocumentsFromPaths, uploadBudgetAttachmentFromPath, uploadQuotationAttachmentFromPath, validateBillSelectionFromPayload, voidCustomerInvoice, whoAmI, } from "./commands.js";
|
|
8
|
+
import { addBudgetItems, approveBill, approveBudget, approveCustomerInvoice, approveQuotation, approveSupplier, archiveItemsByIds, checkCustomerInvoiceReadiness, checkProjectReconciliation, cleanupStagedBillAttachments, cleanupStagedQuotationAttachments, completeProject, createApiKeyForUser, createBillApproval, createBillFromPayload, createBudgetApproval, createBudgetCategory, createBudgetFromPayload, createCompany, createContactPersonFromPayload, createCustomerInvoice, createEstimate, createInboundSource, createItemCategory, createItemFromPayload, createPlaceholderBillForBudgetItem, createProject, createQuotationFromPayload, createSupplierCertification, createSupplierFromPayload, createSupplierPaymentMethod, createSupplierRoleOption, createSupplierTagOption, createUser, deleteBillById, deleteBudgetById, deleteBudgetCategory, deleteBudgetCommission, deleteBudgetDiscount, deleteCompanyById, deleteCustomerInvoice, deleteItemById, deleteItemCategoriesByIds, deleteProjectById, deleteQuotationById, deleteSuppliersByIds, discardCreatingCustomerInvoice, downloadCustomerInvoicePdf, downloadQuotationPdf, getApprovedBudgets, getBillAttachments, getBillDetails, getBudget, getBudgetCategories, getBudgetCategoryBenchmarks, getBudgetDetails, getBudgetItemsOnly, getBudgetVersions, getCompany, getCustomerInvoice, getCustomerInvoiceEmailContext, getDashboard, getErrorMetrics, getEstimatePerformance, getFinancialOverview, getInboundSource, getInboundSubmission, getItem, getItemPricingHistory, getMonthlyMetrics, getProject, getProjectHubStatus, getQuotationDetails, getRecentErrors, getSupplierAnalytics, getSupplierDetails, getSupplierPricingHistory, getSystemOverview, getUserPerformance, importQuickBooksProjectId, listApiKeysForUser, listApprovals, listBills, listBudgets, listCompanies, listContacts, listCustomerInvoices, listEligibleCustomerInvoiceBudgets, listInboundSources, listInboundSubmissions, listIntegrationOperations, listItemCategories, listItems, listProjectHubs, listProjects, listQuotations, listSuppliers, listUsers, markBudgetWonWithProof, patchBillInvoiceNumber, patchBillPayment, reactivateSuppliersByIds, reconcileProject, rejectBill, rejectBudget, rejectCustomerInvoice, rejectQuotation, rejectSupplier, removeBudgetItem, renameBudgetVersion, reorderBudgetItemsCli, restoreBudgetVersion, retryIntegrationOperation, revokeApiKeyForUser, saveInboundAutomationConfig, saveInboundMappingVersion, sendCustomerInvoiceToContactPersonFromPayload, sendEstimateToContactPersonFromPayload, setBudgetItemsNotUtilized, setupProjectHub, stageBillAttachmentsFromPaths, submitQuotation, syncCustomerInvoice, syncProjectHubCommercialDocuments, updateBillFromPayload, updateBillPaymentEvidenceFromPayload, updateBillStatus, updateBudgetCategory, updateBudgetCommissionFromPayload, updateBudgetDiscountFromPayload, updateBudgetFromPayload, updateBudgetItem, updateBudgetItemSupplierCli, updateBudgetStatus, updateCompanyFromPayload, updateContactPersonFromPayload, updateInboundProcessing, updateInboundSource, updateItemCategory, updateItemFromPayload, updateProjectFromPayload, updateProjectStatus, updateQuotationFromPayload, updateSupplierFromPayload, uploadBillAttachmentFromPath, uploadBillAttachmentsFromPaths, uploadBillDocumentsFromPaths, uploadBudgetAttachmentFromPath, uploadQuotationAttachmentFromPath, validateBillSelectionFromPayload, voidCustomerInvoice, whoAmI, } from "./commands.js";
|
|
9
9
|
import { getFlag, parseArgs } from "./parse-args.js";
|
|
10
|
-
import { billStatusesForUpdateHelp, budgetStatusesForHelp, isBudgetStatusUpdate, parseApprovalTypeFlag, parseBillStatusForUpdate, parseCommaSeparatedBillStatuses, parseCommaSeparatedBudgetStatuses, parseCommaSeparatedCustomerInvoiceStatuses, parseCommaSeparatedIds, parseCommaSeparatedIntegrationOperationStatuses, parseCommaSeparatedQuotationStatuses, parseCommaSeparatedSupplierStatuses, parseOptionalBillListSortBy, parseOptionalBillListSortDir, parseOptionalDashboardRole, parseOptionalDeals, parseOptionalErrorSeverity, parseOptionalErrorStatus, parseOptionalExtendedProjectStatus, parseOptionalFinancialRole, parseOptionalSupplierAnalyticsTimeFrame, parseOptionalTimeFrame, parseProjectStatusForUpdate, parseUserRole, projectStatusesForHelp, userRolesForHelp, } from "./parse-cli-enums.js";
|
|
10
|
+
import { billStatusesForUpdateHelp, budgetStatusesForHelp, isBudgetStatusUpdate, parseApprovalTypeFlag, parseBillStatusForUpdate, parseCommaSeparatedBillStatuses, parseCommaSeparatedBudgetStatuses, parseCommaSeparatedCustomerInvoiceStatuses, parseCommaSeparatedIds, parseCommaSeparatedIntegrationOperationStatuses, parseCommaSeparatedProjectStatuses, parseCommaSeparatedQuotationStatuses, parseCommaSeparatedSupplierStatuses, parseOptionalBillListSortBy, parseOptionalBillListSortDir, parseOptionalDashboardRole, parseOptionalDeals, parseOptionalErrorSeverity, parseOptionalErrorStatus, parseOptionalExtendedProjectStatus, parseOptionalFinancialRole, parseOptionalProjectHubSortBy, parseOptionalSupplierAnalyticsTimeFrame, parseOptionalTimeFrame, parseProjectStatusForUpdate, parseUserRole, projectStatusesForHelp, userRolesForHelp, } from "./parse-cli-enums.js";
|
|
11
11
|
import { parseJsonFlag, parseOptionalNumber as parseOptNum, } from "./parse-json-flag.js";
|
|
12
12
|
import { createCompletionScript, createHumanHelp, resolveCommand, } from "./registry/index.js";
|
|
13
13
|
import { CliRuntimeError, clearActiveCliSession, confirmCurrentCommand, createProcessRuntime, emitCommandError, emitCommandResult, setActiveCliSession, } from "./runtime/index.js";
|
|
@@ -155,6 +155,9 @@ AI agents must inspect the entity first, summarize the exact entity, target
|
|
|
155
155
|
state, and side effects, then wait for explicit user confirmation before running
|
|
156
156
|
the sensitive command.
|
|
157
157
|
|
|
158
|
+
Budget mutations return a conflict while an estimate email is queued,
|
|
159
|
+
processing, or awaiting provider reconciliation.
|
|
160
|
+
|
|
158
161
|
Budgets
|
|
159
162
|
list-budgets [--projectId] [--name] [--status CSV] [--createdBy] [--dateFrom] [--dateTo] [--sortBy] [--sortDir] [--page] [--perPage] [--summary]
|
|
160
163
|
get-budget <id> Budget + line items
|
|
@@ -220,7 +223,8 @@ Bills
|
|
|
220
223
|
get-bill-details <billId>
|
|
221
224
|
|
|
222
225
|
Quotations
|
|
223
|
-
list-quotations [--projectId] [--budgetId] [--supplierId] [--status CSV] [--
|
|
226
|
+
list-quotations [--projectId] [--budgetId] [--supplierId] [--status CSV] [--createdBy CSV] [--search] [--page] [--perPage]
|
|
227
|
+
Legacy aliases --requesterIds and --pageSize remain supported.
|
|
224
228
|
get-quotation <quotationId>
|
|
225
229
|
upload-quotation-attachment <projectId> <filePath> Upload one PDF, JPEG, or PNG up to 20MB; returns attachment JSON for a quotation payload.
|
|
226
230
|
cleanup-staged-quotation-attachments <projectId> --keys <csv> Delete unattached staged quotation uploads.
|
|
@@ -267,6 +271,8 @@ Companies & projects
|
|
|
267
271
|
delete-company <id>
|
|
268
272
|
list-projects [--companyId] [--name] [--status] [--active true|false] [--page] [--perPage]
|
|
269
273
|
Omit --active to include both active and inactive projects.
|
|
274
|
+
list-project-hubs [--q] [--status CSV] [--page] [--perPage] [--sortBy startDate|name|companyName|status] [--sortDir asc|desc]
|
|
275
|
+
List active projects that have a Project Hub integration.
|
|
270
276
|
get-project <id>
|
|
271
277
|
Budget overview totalRevenue includes Estimate Accepted and Estimate Closed budgets only.
|
|
272
278
|
create-project --name --companyId --contactPersonId --insideSalesId --businessDevelopmentId --venue --startDate <ISO> [--projectManagerId <userId>] [--asanaTaskId] [--asanaSearch <text>] [--slackChannelId --slackChannelUrl --slackChannelName] [--pax] [--endDate <ISO>] [--description]
|
|
@@ -330,7 +336,7 @@ Errors
|
|
|
330
336
|
|
|
331
337
|
Automation (admin)
|
|
332
338
|
list-integration-operations [--search] [--destination <provider,...>] [--status <PENDING|PROCESSING|FAILED|COMPLETED,...>] [--page] [--perPage]
|
|
333
|
-
retry-integration-operation <operationId> [--confirmExternalStateReconciled true|false]
|
|
339
|
+
retry-integration-operation <operationId> [--confirmExternalStateReconciled true|false] [--outboundEmailResolution ACCEPTED|NOT_ACCEPTED_RETRY] [--providerMessageId <id>]
|
|
334
340
|
|
|
335
341
|
Historical / benchmarks
|
|
336
342
|
get-approved-budgets [--projectId] [--limit] [--minRevenue] [--maxRevenue]
|
|
@@ -1209,19 +1215,19 @@ export async function runCli(argv = process.argv, runtime = createProcessRuntime
|
|
|
1209
1215
|
}
|
|
1210
1216
|
case "list-quotations": {
|
|
1211
1217
|
const statusRaw = getFlag(flags, "status");
|
|
1218
|
+
const createdByRaw = getFlag(flags, "createdBy") ?? getFlag(flags, "requesterIds");
|
|
1219
|
+
const perPageRaw = getFlag(flags, "perPage") ?? getFlag(flags, "pageSize");
|
|
1212
1220
|
await listQuotations({
|
|
1213
1221
|
projectId: getFlag(flags, "projectId"),
|
|
1214
1222
|
budgetId: getFlag(flags, "budgetId"),
|
|
1215
1223
|
supplierId: getFlag(flags, "supplierId"),
|
|
1216
1224
|
status: parseCommaSeparatedQuotationStatuses(statusRaw),
|
|
1217
|
-
|
|
1225
|
+
createdBy: parseCommaSeparatedIds(createdByRaw),
|
|
1218
1226
|
search: getFlag(flags, "search"),
|
|
1219
1227
|
page: getFlag(flags, "page") !== undefined
|
|
1220
1228
|
? Number(getFlag(flags, "page"))
|
|
1221
1229
|
: undefined,
|
|
1222
|
-
|
|
1223
|
-
? Number(getFlag(flags, "pageSize"))
|
|
1224
|
-
: undefined,
|
|
1230
|
+
perPage: perPageRaw !== undefined ? Number(perPageRaw) : undefined,
|
|
1225
1231
|
});
|
|
1226
1232
|
break;
|
|
1227
1233
|
}
|
|
@@ -1568,6 +1574,17 @@ export async function runCli(argv = process.argv, runtime = createProcessRuntime
|
|
|
1568
1574
|
});
|
|
1569
1575
|
break;
|
|
1570
1576
|
}
|
|
1577
|
+
case "list-project-hubs": {
|
|
1578
|
+
await listProjectHubs({
|
|
1579
|
+
q: getFlag(flags, "q"),
|
|
1580
|
+
statuses: parseCommaSeparatedProjectStatuses(getFlag(flags, "status")),
|
|
1581
|
+
page: parsePositiveIntFlag(getFlag(flags, "page"), "--page"),
|
|
1582
|
+
perPage: parsePositiveIntFlag(getFlag(flags, "perPage"), "--perPage"),
|
|
1583
|
+
sortBy: parseOptionalProjectHubSortBy(getFlag(flags, "sortBy")),
|
|
1584
|
+
sortDir: parseOptionalBillListSortDir(getFlag(flags, "sortDir")),
|
|
1585
|
+
});
|
|
1586
|
+
break;
|
|
1587
|
+
}
|
|
1571
1588
|
case "get-project": {
|
|
1572
1589
|
const id = positional[0];
|
|
1573
1590
|
if (!id)
|
|
@@ -2007,8 +2024,14 @@ export async function runCli(argv = process.argv, runtime = createProcessRuntime
|
|
|
2007
2024
|
if (!operationId) {
|
|
2008
2025
|
throw new Error("retry-integration-operation requires <operationId>");
|
|
2009
2026
|
}
|
|
2027
|
+
const outboundEmailResolution = getFlag(flags, "outboundEmailResolution");
|
|
2028
|
+
if (outboundEmailResolution &&
|
|
2029
|
+
outboundEmailResolution !== "ACCEPTED" &&
|
|
2030
|
+
outboundEmailResolution !== "NOT_ACCEPTED_RETRY") {
|
|
2031
|
+
throw new Error("--outboundEmailResolution must be ACCEPTED or NOT_ACCEPTED_RETRY");
|
|
2032
|
+
}
|
|
2010
2033
|
await retryIntegrationOperation(operationId, parseOptionalBoolFlag(flags, "confirmExternalStateReconciled") ??
|
|
2011
|
-
false);
|
|
2034
|
+
false, outboundEmailResolution, getFlag(flags, "providerMessageId"));
|
|
2012
2035
|
break;
|
|
2013
2036
|
}
|
|
2014
2037
|
case "list-inbound-sources": {
|
package/dist/parse-cli-enums.js
CHANGED
|
@@ -78,6 +78,36 @@ export function parseOptionalExtendedProjectStatus(raw) {
|
|
|
78
78
|
}
|
|
79
79
|
return raw;
|
|
80
80
|
}
|
|
81
|
+
export function parseCommaSeparatedProjectStatuses(raw) {
|
|
82
|
+
if (raw === undefined)
|
|
83
|
+
return undefined;
|
|
84
|
+
const statuses = raw
|
|
85
|
+
.split(",")
|
|
86
|
+
.map((value) => value.trim().toUpperCase())
|
|
87
|
+
.filter(Boolean);
|
|
88
|
+
if (statuses.length === 0)
|
|
89
|
+
return undefined;
|
|
90
|
+
for (const status of statuses) {
|
|
91
|
+
if (!PROJECT_STATUS_VALUES.has(status)) {
|
|
92
|
+
throw new Error(`Invalid project status "${status}". Use one of: ${[...PROJECT_STATUS_VALUES].join(", ")}.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return statuses;
|
|
96
|
+
}
|
|
97
|
+
const PROJECT_HUB_SORT_FIELDS = new Set([
|
|
98
|
+
"startDate",
|
|
99
|
+
"name",
|
|
100
|
+
"companyName",
|
|
101
|
+
"status",
|
|
102
|
+
]);
|
|
103
|
+
export function parseOptionalProjectHubSortBy(raw) {
|
|
104
|
+
if (raw === undefined || raw === "")
|
|
105
|
+
return undefined;
|
|
106
|
+
if (!PROJECT_HUB_SORT_FIELDS.has(raw)) {
|
|
107
|
+
throw new Error(`Invalid --sortBy "${raw}". Use one of: ${[...PROJECT_HUB_SORT_FIELDS].join(", ")}.`);
|
|
108
|
+
}
|
|
109
|
+
return raw;
|
|
110
|
+
}
|
|
81
111
|
export function parseOptionalDashboardRole(raw) {
|
|
82
112
|
if (raw === undefined || raw === "")
|
|
83
113
|
return undefined;
|
package/dist/registry/index.js
CHANGED
|
@@ -192,6 +192,9 @@ const titleCase = (value) => value
|
|
|
192
192
|
const summaryFor = (legacyTarget) => {
|
|
193
193
|
if (legacyTarget === "whoami")
|
|
194
194
|
return "Show the active API-key identity.";
|
|
195
|
+
if (legacyTarget === "download-customer-invoice-pdf") {
|
|
196
|
+
return "Download a customer invoice PDF when permitted.";
|
|
197
|
+
}
|
|
195
198
|
if (legacyTarget.startsWith("list-")) {
|
|
196
199
|
return `List ${legacyTarget.slice("list-".length).replaceAll("-", " ")}.`;
|
|
197
200
|
}
|
|
@@ -206,11 +209,11 @@ const aliasesFor = (legacyTarget, aliases) => [
|
|
|
206
209
|
alias.replaceAll("-", "_"),
|
|
207
210
|
])),
|
|
208
211
|
];
|
|
209
|
-
const legacyCommand = (legacyTarget, path, aliases = []) => ({
|
|
212
|
+
const legacyCommand = (legacyTarget, path, aliases = [], commandOptions = []) => ({
|
|
210
213
|
path,
|
|
211
214
|
legacyAliases: aliasesFor(legacyTarget, aliases),
|
|
212
215
|
summary: summaryFor(legacyTarget),
|
|
213
|
-
options: globalCommandOptions,
|
|
216
|
+
options: [...globalCommandOptions, ...commandOptions],
|
|
214
217
|
effects: effectsFor(legacyTarget),
|
|
215
218
|
legacyTarget,
|
|
216
219
|
});
|
|
@@ -364,6 +367,23 @@ const registry = [
|
|
|
364
367
|
legacyCommand("update-company", ["company", "update"]),
|
|
365
368
|
legacyCommand("delete-company", ["company", "delete"]),
|
|
366
369
|
legacyCommand("list-projects", ["project", "list"]),
|
|
370
|
+
legacyCommand("list-project-hubs", ["project", "hub", "list"], [], [
|
|
371
|
+
{
|
|
372
|
+
name: "--q",
|
|
373
|
+
description: "Search project and company names.",
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "--status",
|
|
377
|
+
description: "Filter by comma-separated project statuses.",
|
|
378
|
+
},
|
|
379
|
+
{ name: "--page", description: "Select a results page." },
|
|
380
|
+
{ name: "--perPage", description: "Set the results page size." },
|
|
381
|
+
{
|
|
382
|
+
name: "--sortBy",
|
|
383
|
+
description: "Sort by startDate, name, companyName, or status.",
|
|
384
|
+
},
|
|
385
|
+
{ name: "--sortDir", description: "Sort in asc or desc order." },
|
|
386
|
+
]),
|
|
367
387
|
legacyCommand("get-project", ["project", "get"]),
|
|
368
388
|
legacyCommand("get-project-hub-status", ["project", "hub", "status"]),
|
|
369
389
|
legacyCommand("setup-project-hub", ["project", "hub", "setup"]),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/bb",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.0",
|
|
4
4
|
"description": "Budget Builder CLI for AI agents — manage budgets, bills, claims, quotations, and customer invoices with explicit workflow previews for sensitive changes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -86,6 +86,7 @@ This table highlights the role-sensitive command groups an agent is most likely
|
|
|
86
86
|
|
|
87
87
|
| Commands or action | Required identity condition |
|
|
88
88
|
| --- | --- |
|
|
89
|
+
| `bb project hub list` | Any active authenticated role; the command is read-only and returns only active projects with a Project Hub integration. |
|
|
89
90
|
| `bb auth whoami`; own `bb user api-key create`, `bb user api-key list`, and `bb user api-key revoke` | Any active role; omit `--userId` to act as the current user. |
|
|
90
91
|
| Cross-user API-key commands; `bb user create` | `ADMIN`. |
|
|
91
92
|
| Budget/project mutations, estimates, and budget attachments | `ADMIN`, budget creator, or project assignment as Business Development, Inside Sales, or Project Manager, depending on the endpoint. |
|
|
@@ -98,6 +99,7 @@ This table highlights the role-sensitive command groups an agent is most likely
|
|
|
98
99
|
| `bb bill status update ... APPROVED` or `... PAID` | `ADMIN`; state, integration, payment-reference, and payment-proof requirements still apply. |
|
|
99
100
|
| `bb bill payment patch`; `bb bill invoice-number patch` | `ACCOUNTING_TEAM` or `ADMIN`, with the procedure's bill-state constraints. |
|
|
100
101
|
| `bb customer-invoice approve` and `bb customer-invoice reject` | `ADMIN` batch operations selected by batch ID; the API resolves the internal pending Admin approval record. |
|
|
102
|
+
| `bb customer-invoice pdf download` | `ADMIN` for pending-approval batches; other roles may download after pending approval. QuickBooks sync errors cannot be previewed or downloaded. |
|
|
101
103
|
| Dashboard/performance, supplier analytics, errors, integration operations | `ADMIN`. |
|
|
102
104
|
| `bb item category create`, `bb item category update`, `bb item category delete`, `bb supplier delete`, `bb supplier reactivate`, and `bb budget item placeholder-bill create` | `ADMIN`. |
|
|
103
105
|
|