@go-labs-sg/bb 2.36.0 → 2.38.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
@@ -193,7 +193,7 @@ Run `bb version` before agent-driven work to record the installed package versio
193
193
 
194
194
  **Authoritative command list:** run `bb help` or inspect the generated `command-reference.md` / `command-manifest.json`. The catalog includes every canonical route, global option, and effect classification, but does not filter by the current `whoami` role. During the handler migration, command-specific arguments retain the compatibility dispatcher's validation and are explicitly marked `legacy-passthrough` in the manifest; use `bb help --legacy` for their detailed transition reference. Version 2 uses grouped, resource-first commands such as `bb budget list` and `bb bill attachment upload`. Flat commands such as `bb list-budgets` and their MCP-style `snake_case` aliases remain available during the v2 transition, with a deprecation notice and an equivalent grouped command in help. MCP exposes a subset of the same tRPC surface; the CLI additionally includes a few procedures mainly used by the web UI.
195
195
 
196
- **Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. The first accepted estimate also requires `--invoiceSettings '<json>'` while customer invoicing is enabled. Provide `depositPercentage`, `balancePercentage`, `deliveryMethod`, and the matching `billingEmail` or HTTPS `uploadUrl`; revenue at or below S$5,000 requires `100/0`. If the parent project is `PITCH` or `LOST`, the API marks it `WON` automatically and runs enabled Asana automation. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
196
+ **Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. `--invoiceSettings '<json>'` remains available when the project needs saved delivery preferences, but invoice creation chooses its amount independently from those settings. If the parent project is `PITCH` or `LOST`, the API marks it `WON` automatically and runs enabled Asana automation. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
197
197
 
198
198
  ### Typeform inbound administration
199
199
 
@@ -306,51 +306,40 @@ Bill creation determines its required permissions from the parsed input, for bot
306
306
 
307
307
  **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.
308
308
 
309
- ### Acceptance invoice splits and grouped sending
309
+ ### Invoice amount, due date, and approval
310
310
 
311
- After `bb budget won mark` (or an accepted status update), the JSON result includes an `invoiceSetup` prompt for QuickBooks-backed estimates. Choose the split amounts and each split's contractual due date; invoice creation does not wait for those due dates. There is no separate split-approval request.
311
+ After accepting an estimate, choose any eligible budget with an uninvoiced balance. Create one invoice at a time for all or part of the remaining estimate percentage. Creation is immediate; the due date is the payment deadline.
312
312
 
313
- 1. `bb customer-invoice splits <budgetId>` returns the current revision, row IDs, billing defaults, and invoice approval/delivery states.
314
- 2. `bb customer-invoice preview-splits --payload '<json>'` previews amounts including GST and due-date changes, without writes.
315
- 3. `bb customer-invoice save-splits --payload '<json>'` saves that setup only. It does not create QBO invoices or request invoice approval. Re-read `splits` for the new revision and instalment IDs.
316
- 4. `bb customer-invoice create-splits --payload '{"budgetId":"budget_1","expectedRevision":2,"instalmentIds":["row_1","row_2"]}'` creates selected ready invoices in QBO. Non-admin creation automatically requests admin approval **after creation**; admin creation auto-approves. No customer email is sent.
317
- 5. An admin uses the existing `bb customer-invoice approve <batchId>` action for each pending invoice batch. Approval does not send the invoice to the customer.
318
- 6. The user re-reads `splits`, then runs `bb customer-invoice send-group --payload '{"budgetId":"budget_1","expectedRevision":2,"instalmentIds":["row_1","row_2"]}'` to send approved invoices together in one email. Select one row for individual sending. Alternatively, use `--all-approved --payload '{"budgetId":"budget_1","expectedRevision":2}'` to select all approved, unsent invoices in that budget. Do not combine `--all-approved` with `instalmentIds`.
313
+ 1. Run `bb customer-invoice eligible-budget list <projectId>` to review each estimate total, already invoiced percentage, remaining percentage, and available amount.
314
+ 2. Run `bb customer-invoice readiness check <budgetId>` for live QuickBooks validation and the full remaining-balance preview.
315
+ 3. For a partial invoice, run `bb customer-invoice amount preview <budgetId> <percentage-of-estimate>` to review the amount before GST, GST, and total. The percentage is based on the original estimate and cannot exceed the remaining percentage.
316
+ 4. Run `bb customer-invoice create --payload '<json>'` with a recommended UUID request ID, invoice date, billing address, customer memo, and exactly one split containing its estimate percentage and due date.
317
+ 5. Non-admin creation automatically requests admin approval after QBO creation. Admin creation is auto-approved. Pending approval never sends invoices.
318
+ 6. Use the normal invoice detail/email or portal-upload actions after approval. Creation and approval do not automatically email the customer.
319
319
 
320
- Preview/save use this shape, populated from the current `splits` result and the signed terms (IDs, addresses, and dates below are examples only):
320
+ Example for a 50% invoice:
321
321
 
322
322
  ```json
323
323
  {
324
324
  "budgetId": "budget_1",
325
- "expectedRevision": 1,
326
- "scope": "BASE",
327
- "changeReason": "Confirmed invoice split and due dates from signed estimate",
328
- "definition": {
329
- "rows": [
330
- { "key": "deposit", "label": "Deposit", "amount": { "type": "PERCENTAGE", "value": 70 }, "due": { "type": "CONFIRMATION" }, "issue": { "type": "ACCEPTANCE" } },
331
- { "key": "balance", "label": "Balance", "amount": { "type": "PERCENTAGE", "value": 30 }, "due": { "type": "FIXED_DATE", "date": "2026-12-01" }, "issue": { "type": "ACCEPTANCE" } }
332
- ],
333
- "reminderLeadDays": 7,
334
- "billingRestriction": ""
325
+ "requestId": "6ec0d99f-24a4-4f3e-9a74-d3f4fd971a25",
326
+ "invoiceDate": "2026-11-21",
327
+ "details": {
328
+ "billingAddress": "Customer name\n1 Example Street\nSingapore 123456",
329
+ "customerMemo": "Thank you for your business."
335
330
  },
336
- "billing": {
337
- "legalEntityName": "Customer legal entity",
338
- "purchaseOrder": "PO-reference",
339
- "billingAddress": "Customer billing address",
340
- "to": "billing@example.invalid",
341
- "cc": [],
342
- "replyTo": "owner@example.invalid",
343
- "deliveryMethod": "EMAIL",
344
- "uploadUrl": null
345
- }
331
+ "isCustomPercentage": true,
332
+ "splits": [
333
+ { "label": "Partial invoice", "percentage": 50, "dueDate": "2026-12-01" }
334
+ ]
346
335
  }
347
336
  ```
348
337
 
349
- Use the exact current revision (or `null` only when no schedule exists). Fixed amounts use **pre-GST cents**; percentages use percentage points. Event-relative due rules are `EVENT_START` or `EVENT_END` with `offsetDays`. Preview and resolve missing dates, past-due review or unresolved amounts rather than inventing replacements.
338
+ Use the exact percentage returned by the preview flow. Non-interactive creation requires `--allow-state-change --allow-financial-write --allow-external-write --allow-email` (internal approval notification, not customer delivery). Reuse the same `requestId` when retrying an uncertain request, and review the existing batch before retrying.
350
339
 
351
- Non-interactive save requires `--allow-state-change`; creation requires `--allow-state-change --allow-financial-write --allow-external-write --allow-email` (approval-request email, not customer invoice delivery); grouped sending requires `--allow-state-change --allow-email --allow-external-write`. These flags acknowledge effects, not role permissions or user authorisation. Both ordinary users and admins still need server-granted project access. Pending/rejected invoices cannot be sent; a mixed selection is rejected rather than silently dropping invoices. Sending uses each issued invoice's original billing revision, not later edits. Invoices with different original billing instructions must be sent in separate groups. Do not blindly retry uncertain QBO or email outcomes.
340
+ To link an invoice that already exists in QuickBooks, first run `bb customer-invoice existing list <budgetId>`. Choose a returned `qboInvoiceId`, review it with `bb customer-invoice preview-qbo <budgetId> <qboInvoiceId>`, then use the preview token with `bb customer-invoice import-qbo <budgetId> <qboInvoiceId> --token <previewToken>`.
352
341
 
353
- These commands require the matching API deployment and a new CLI release; changing this repository does not publish the CLI or deploy production.
342
+ The former `splits`, `preview-splits`, `save-splits`, `create-splits`, and `send-group` schedule commands are retired. Update the CLI alongside the API. Existing schedule data and invoices are retained, and previously queued emails retain their delivery/reconciliation support; no new schedules or reminders are created.
354
343
 
355
344
  ### Quotation amounts and line allocations
356
345
 
@@ -467,7 +456,7 @@ Bill, claim, and quotation mutations accept only suppliers whose approval status
467
456
  | **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`; cloned unavailable lines require `unavailableItemReviewAcknowledged: true`), `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`, `replace-budget-item`, `approve-unavailable-item-exception` (Lead/Admin), `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`) |
468
457
  | **Bills / claims** | `list-bills` (`--isClaimable false` for bills, `--isClaimable true` for claims, omit for both), `list-claims` (claims only), `validate-bill-selection` (`--payload`, plus `--quotationIds q1,q2` or legacy `--quotationId q1`; validates the approved supplier and quotation coverage), `link-bill-quotations` (`<billId> --quotationIds q1,q2`; Admin source-link repair for eligible supplier bills), `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 and provide approved `quotationIds`, or use `--quotation-exempt` for an eligible server-validated exemption; set `isClaimable=true` for a claim without quotations; supplier bills require positive **before-GST** `extractedAmount` (full invoice subtotal) and `amount` (portion billed), with `amount <= extractedAmount`; line and quotation allocation amounts also exclude GST; 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), `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` |
469
458
  | **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`, `gstAmount`, and `lineAmounts` entries `{ budgetItemId, amount }` for multiple selected items), `update-quotation` (`--payload`; updates a `DRAFT` or `REJECTED` quotation), `delete-quotation`, `submit-quotation`, `approve-quotation`, `reject-quotation`, `download-quotation-pdf` (`original`, `staff`, or `final`) |
470
- | **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `list-customer-invoices` (global/project/budget filters plus summary metrics; `--sortBy totalInvoiceAmount` sorts provider-confirmed totals including GST, with unknown amounts last), `get-customer-invoice`, `get-customer-invoice-email-context`, `preview-qbo-customer-invoice`, `import-qbo-customer-invoice` (BB-only link with reviewed token), `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` |
459
+ | **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `preview-customer-invoice-amount`, `list-available-qbo-customer-invoices`, `list-customer-invoices` (global/project/budget filters plus summary metrics; `--sortBy totalInvoiceAmount` sorts provider-confirmed totals including GST, with unknown amounts last), `get-customer-invoice`, `get-customer-invoice-email-context`, `preview-qbo-customer-invoice`, `import-qbo-customer-invoice` (BB-only link with reviewed token), `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` |
471
460
  | **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` |
472
461
  | **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`) |
473
462
  | **Contacts** | `list-contacts`, `create-contact-person` (`--payload`), `update-contact-person` (`--payload`) |
@@ -3571,112 +3571,12 @@
3571
3571
  "legacyTarget": "list-eligible-customer-invoice-budgets"
3572
3572
  },
3573
3573
  {
3574
- "path": ["customer-invoice", "list"],
3575
- "legacyAliases": ["list-customer-invoices", "list_customer_invoices"],
3576
- "summary": "List customer invoices.",
3577
- "globalOptions": [
3578
- {
3579
- "name": "--help",
3580
- "description": "Show help for this command."
3581
- },
3582
- {
3583
- "name": "--quiet",
3584
- "description": "Suppress non-error diagnostics."
3585
- },
3586
- {
3587
- "name": "--debug",
3588
- "description": "Emit sanitized diagnostic traces."
3589
- },
3590
- {
3591
- "name": "--api-url",
3592
- "description": "Override the Budget Builder API base URL."
3593
- },
3594
- {
3595
- "name": "--no-browser",
3596
- "description": "Print the authorization URL without opening a browser."
3597
- },
3598
- {
3599
- "name": "--allow-state-change",
3600
- "description": "Allow a Budget Builder state change in non-interactive use."
3601
- },
3602
- {
3603
- "name": "--allow-email",
3604
- "description": "Allow sending email in non-interactive use."
3605
- },
3606
- {
3607
- "name": "--allow-external-write",
3608
- "description": "Allow writes to external systems in non-interactive use."
3609
- },
3610
- {
3611
- "name": "--allow-delete",
3612
- "description": "Allow deleting data in non-interactive use."
3613
- },
3614
- {
3615
- "name": "--allow-financial-write",
3616
- "description": "Allow financial-record changes in non-interactive use."
3617
- }
3618
- ],
3619
- "argumentMode": "legacy-passthrough",
3620
- "effects": [],
3621
- "legacyTarget": "list-customer-invoices"
3622
- },
3623
- {
3624
- "path": ["customer-invoice", "get"],
3625
- "legacyAliases": ["get-customer-invoice", "get_customer_invoice"],
3626
- "summary": "Get customer invoice.",
3627
- "globalOptions": [
3628
- {
3629
- "name": "--help",
3630
- "description": "Show help for this command."
3631
- },
3632
- {
3633
- "name": "--quiet",
3634
- "description": "Suppress non-error diagnostics."
3635
- },
3636
- {
3637
- "name": "--debug",
3638
- "description": "Emit sanitized diagnostic traces."
3639
- },
3640
- {
3641
- "name": "--api-url",
3642
- "description": "Override the Budget Builder API base URL."
3643
- },
3644
- {
3645
- "name": "--no-browser",
3646
- "description": "Print the authorization URL without opening a browser."
3647
- },
3648
- {
3649
- "name": "--allow-state-change",
3650
- "description": "Allow a Budget Builder state change in non-interactive use."
3651
- },
3652
- {
3653
- "name": "--allow-email",
3654
- "description": "Allow sending email in non-interactive use."
3655
- },
3656
- {
3657
- "name": "--allow-external-write",
3658
- "description": "Allow writes to external systems in non-interactive use."
3659
- },
3660
- {
3661
- "name": "--allow-delete",
3662
- "description": "Allow deleting data in non-interactive use."
3663
- },
3664
- {
3665
- "name": "--allow-financial-write",
3666
- "description": "Allow financial-record changes in non-interactive use."
3667
- }
3668
- ],
3669
- "argumentMode": "legacy-passthrough",
3670
- "effects": [],
3671
- "legacyTarget": "get-customer-invoice"
3672
- },
3673
- {
3674
- "path": ["customer-invoice", "email-context", "get"],
3574
+ "path": ["customer-invoice", "amount", "preview"],
3675
3575
  "legacyAliases": [
3676
- "get-customer-invoice-email-context",
3677
- "get_customer_invoice_email_context"
3576
+ "preview-customer-invoice-amount",
3577
+ "preview_customer_invoice_amount"
3678
3578
  ],
3679
- "summary": "Get customer invoice email context.",
3579
+ "summary": "Preview amount before GST, GST, and total for a percentage of an accepted estimate. Arguments: <budgetId> <percentage-of-estimate>.",
3680
3580
  "globalOptions": [
3681
3581
  {
3682
3582
  "name": "--help",
@@ -3721,15 +3621,15 @@
3721
3621
  ],
3722
3622
  "argumentMode": "legacy-passthrough",
3723
3623
  "effects": [],
3724
- "legacyTarget": "get-customer-invoice-email-context"
3624
+ "legacyTarget": "preview-customer-invoice-amount"
3725
3625
  },
3726
3626
  {
3727
- "path": ["customer-invoice", "preview-qbo"],
3627
+ "path": ["customer-invoice", "existing", "list"],
3728
3628
  "legacyAliases": [
3729
- "preview-qbo-customer-invoice",
3730
- "preview_qbo_customer_invoice"
3629
+ "list-available-qbo-customer-invoices",
3630
+ "list_available_qbo_customer_invoices"
3731
3631
  ],
3732
- "summary": "Preview an existing QuickBooks invoice for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.",
3632
+ "summary": "List unlinked QuickBooks invoices available for an accepted or closed estimate. Argument: <budgetId>.",
3733
3633
  "globalOptions": [
3734
3634
  {
3735
3635
  "name": "--help",
@@ -3774,68 +3674,12 @@
3774
3674
  ],
3775
3675
  "argumentMode": "legacy-passthrough",
3776
3676
  "effects": [],
3777
- "legacyTarget": "preview-qbo-customer-invoice"
3677
+ "legacyTarget": "list-available-qbo-customer-invoices"
3778
3678
  },
3779
3679
  {
3780
- "path": ["customer-invoice", "import-qbo"],
3781
- "legacyAliases": [
3782
- "import-qbo-customer-invoice",
3783
- "import_qbo_customer_invoice"
3784
- ],
3785
- "summary": "Link an existing QuickBooks invoice in BB only after reviewing preview-qbo. Arguments: <budgetId> <qboInvoiceId> --token <previewToken>. Supports closed estimates; no QBO writes or emails.",
3786
- "globalOptions": [
3787
- {
3788
- "name": "--help",
3789
- "description": "Show help for this command."
3790
- },
3791
- {
3792
- "name": "--quiet",
3793
- "description": "Suppress non-error diagnostics."
3794
- },
3795
- {
3796
- "name": "--debug",
3797
- "description": "Emit sanitized diagnostic traces."
3798
- },
3799
- {
3800
- "name": "--api-url",
3801
- "description": "Override the Budget Builder API base URL."
3802
- },
3803
- {
3804
- "name": "--no-browser",
3805
- "description": "Print the authorization URL without opening a browser."
3806
- },
3807
- {
3808
- "name": "--allow-state-change",
3809
- "description": "Allow a Budget Builder state change in non-interactive use."
3810
- },
3811
- {
3812
- "name": "--allow-email",
3813
- "description": "Allow sending email in non-interactive use."
3814
- },
3815
- {
3816
- "name": "--allow-external-write",
3817
- "description": "Allow writes to external systems in non-interactive use."
3818
- },
3819
- {
3820
- "name": "--allow-delete",
3821
- "description": "Allow deleting data in non-interactive use."
3822
- },
3823
- {
3824
- "name": "--allow-financial-write",
3825
- "description": "Allow financial-record changes in non-interactive use."
3826
- }
3827
- ],
3828
- "argumentMode": "legacy-passthrough",
3829
- "effects": ["state-change", "financial-write"],
3830
- "legacyTarget": "import-qbo-customer-invoice"
3831
- },
3832
- {
3833
- "path": ["customer-invoice", "splits"],
3834
- "legacyAliases": [
3835
- "get-customer-invoice-splits",
3836
- "get_customer_invoice_splits"
3837
- ],
3838
- "summary": "Review acceptance invoice splits, due dates, approval states and saved billing details. Arguments: <budgetId>.",
3680
+ "path": ["customer-invoice", "list"],
3681
+ "legacyAliases": ["list-customer-invoices", "list_customer_invoices"],
3682
+ "summary": "List customer invoices.",
3839
3683
  "globalOptions": [
3840
3684
  {
3841
3685
  "name": "--help",
@@ -3880,15 +3724,12 @@
3880
3724
  ],
3881
3725
  "argumentMode": "legacy-passthrough",
3882
3726
  "effects": [],
3883
- "legacyTarget": "get-customer-invoice-splits"
3727
+ "legacyTarget": "list-customer-invoices"
3884
3728
  },
3885
3729
  {
3886
- "path": ["customer-invoice", "preview-splits"],
3887
- "legacyAliases": [
3888
- "preview-customer-invoice-splits",
3889
- "preview_customer_invoice_splits"
3890
- ],
3891
- "summary": "Preview splits, GST totals and due-date changes without writes. Requires --payload with the schedule save input.",
3730
+ "path": ["customer-invoice", "get"],
3731
+ "legacyAliases": ["get-customer-invoice", "get_customer_invoice"],
3732
+ "summary": "Get customer invoice.",
3892
3733
  "globalOptions": [
3893
3734
  {
3894
3735
  "name": "--help",
@@ -3933,15 +3774,15 @@
3933
3774
  ],
3934
3775
  "argumentMode": "legacy-passthrough",
3935
3776
  "effects": [],
3936
- "legacyTarget": "preview-customer-invoice-splits"
3777
+ "legacyTarget": "get-customer-invoice"
3937
3778
  },
3938
3779
  {
3939
- "path": ["customer-invoice", "save-splits"],
3780
+ "path": ["customer-invoice", "email-context", "get"],
3940
3781
  "legacyAliases": [
3941
- "save-customer-invoice-splits",
3942
- "save_customer_invoice_splits"
3782
+ "get-customer-invoice-email-context",
3783
+ "get_customer_invoice_email_context"
3943
3784
  ],
3944
- "summary": "Save split amounts and separate due dates after estimate acceptance. Requires --payload; does not create invoices or request approval.",
3785
+ "summary": "Get customer invoice email context.",
3945
3786
  "globalOptions": [
3946
3787
  {
3947
3788
  "name": "--help",
@@ -3985,16 +3826,16 @@
3985
3826
  }
3986
3827
  ],
3987
3828
  "argumentMode": "legacy-passthrough",
3988
- "effects": ["state-change"],
3989
- "legacyTarget": "save-customer-invoice-splits"
3829
+ "effects": [],
3830
+ "legacyTarget": "get-customer-invoice-email-context"
3990
3831
  },
3991
3832
  {
3992
- "path": ["customer-invoice", "create-splits"],
3833
+ "path": ["customer-invoice", "preview-qbo"],
3993
3834
  "legacyAliases": [
3994
- "create-customer-invoice-splits",
3995
- "create_customer_invoice_splits"
3835
+ "preview-qbo-customer-invoice",
3836
+ "preview_qbo_customer_invoice"
3996
3837
  ],
3997
- "summary": "Create selected split invoices in QBO, then request admin approval for non-admin creators or auto-approve admin creators. Requires --payload with budgetId, expectedRevision, instalmentIds. Never sends customer invoices.",
3838
+ "summary": "Preview an available QuickBooks invoice selected for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.",
3998
3839
  "globalOptions": [
3999
3840
  {
4000
3841
  "name": "--help",
@@ -4038,16 +3879,16 @@
4038
3879
  }
4039
3880
  ],
4040
3881
  "argumentMode": "legacy-passthrough",
4041
- "effects": ["state-change", "financial-write", "external-write", "email"],
4042
- "legacyTarget": "create-customer-invoice-splits"
3882
+ "effects": [],
3883
+ "legacyTarget": "preview-qbo-customer-invoice"
4043
3884
  },
4044
3885
  {
4045
- "path": ["customer-invoice", "send-group"],
3886
+ "path": ["customer-invoice", "import-qbo"],
4046
3887
  "legacyAliases": [
4047
- "send-customer-invoice-group",
4048
- "send_customer_invoice_group"
3888
+ "import-qbo-customer-invoice",
3889
+ "import_qbo_customer_invoice"
4049
3890
  ],
4050
- "summary": "Send selected approved invoices together in one email. Requires --payload with budgetId, expectedRevision, instalmentIds, or --all-approved without instalmentIds. Pass one instalment for individual sending.",
3891
+ "summary": "Link an existing QuickBooks invoice in BB only after reviewing preview-qbo. Arguments: <budgetId> <qboInvoiceId> --token <previewToken>. Supports closed estimates; no QBO writes or emails.",
4051
3892
  "globalOptions": [
4052
3893
  {
4053
3894
  "name": "--help",
@@ -4088,20 +3929,16 @@
4088
3929
  {
4089
3930
  "name": "--allow-financial-write",
4090
3931
  "description": "Allow financial-record changes in non-interactive use."
4091
- },
4092
- {
4093
- "name": "--all-approved",
4094
- "description": "Select all approved unsent invoices; payload must contain only budgetId and expectedRevision."
4095
3932
  }
4096
3933
  ],
4097
3934
  "argumentMode": "legacy-passthrough",
4098
- "effects": ["state-change", "email", "external-write"],
4099
- "legacyTarget": "send-customer-invoice-group"
3935
+ "effects": ["state-change", "financial-write"],
3936
+ "legacyTarget": "import-qbo-customer-invoice"
4100
3937
  },
4101
3938
  {
4102
3939
  "path": ["customer-invoice", "create"],
4103
3940
  "legacyAliases": ["create-customer-invoice", "create_customer_invoice"],
4104
- "summary": "Create Customer Invoice.",
3941
+ "summary": "Create one invoice from an eligible budget using --payload JSON with invoice date, due date, billing address, customer memo, and a percentage of the original estimate that does not exceed its remaining coverage.",
4105
3942
  "globalOptions": [
4106
3943
  {
4107
3944
  "name": "--help",
@@ -577,6 +577,22 @@ Legacy aliases: `list-eligible-customer-invoice-budgets`, `list_eligible_custome
577
577
 
578
578
  Effects: none.
579
579
 
580
+ ## `bb customer-invoice amount preview`
581
+
582
+ Preview amount before GST, GST, and total for a percentage of an accepted estimate. Arguments: <budgetId> <percentage-of-estimate>.
583
+
584
+ Legacy aliases: `preview-customer-invoice-amount`, `preview_customer_invoice_amount`.
585
+
586
+ Effects: none.
587
+
588
+ ## `bb customer-invoice existing list`
589
+
590
+ List unlinked QuickBooks invoices available for an accepted or closed estimate. Argument: <budgetId>.
591
+
592
+ Legacy aliases: `list-available-qbo-customer-invoices`, `list_available_qbo_customer_invoices`.
593
+
594
+ Effects: none.
595
+
580
596
  ## `bb customer-invoice list`
581
597
 
582
598
  List customer invoices.
@@ -603,7 +619,7 @@ Effects: none.
603
619
 
604
620
  ## `bb customer-invoice preview-qbo`
605
621
 
606
- Preview an existing QuickBooks invoice for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.
622
+ Preview an available QuickBooks invoice selected for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.
607
623
 
608
624
  Legacy aliases: `preview-qbo-customer-invoice`, `preview_qbo_customer_invoice`.
609
625
 
@@ -617,49 +633,9 @@ Legacy aliases: `import-qbo-customer-invoice`, `import_qbo_customer_invoice`.
617
633
 
618
634
  Effects: state-change, financial-write.
619
635
 
620
- ## `bb customer-invoice splits`
621
-
622
- Review acceptance invoice splits, due dates, approval states and saved billing details. Arguments: <budgetId>.
623
-
624
- Legacy aliases: `get-customer-invoice-splits`, `get_customer_invoice_splits`.
625
-
626
- Effects: none.
627
-
628
- ## `bb customer-invoice preview-splits`
629
-
630
- Preview splits, GST totals and due-date changes without writes. Requires --payload with the schedule save input.
631
-
632
- Legacy aliases: `preview-customer-invoice-splits`, `preview_customer_invoice_splits`.
633
-
634
- Effects: none.
635
-
636
- ## `bb customer-invoice save-splits`
637
-
638
- Save split amounts and separate due dates after estimate acceptance. Requires --payload; does not create invoices or request approval.
639
-
640
- Legacy aliases: `save-customer-invoice-splits`, `save_customer_invoice_splits`.
641
-
642
- Effects: state-change.
643
-
644
- ## `bb customer-invoice create-splits`
645
-
646
- Create selected split invoices in QBO, then request admin approval for non-admin creators or auto-approve admin creators. Requires --payload with budgetId, expectedRevision, instalmentIds. Never sends customer invoices.
647
-
648
- Legacy aliases: `create-customer-invoice-splits`, `create_customer_invoice_splits`.
649
-
650
- Effects: state-change, financial-write, external-write, email.
651
-
652
- ## `bb customer-invoice send-group`
653
-
654
- Send selected approved invoices together in one email. Requires --payload with budgetId, expectedRevision, instalmentIds, or --all-approved without instalmentIds. Pass one instalment for individual sending.
655
-
656
- Legacy aliases: `send-customer-invoice-group`, `send_customer_invoice_group`.
657
-
658
- Effects: state-change, email, external-write.
659
-
660
636
  ## `bb customer-invoice create`
661
637
 
662
- Create Customer Invoice.
638
+ Create one invoice from an eligible budget using --payload JSON with invoice date, due date, billing address, customer memo, and a percentage of the original estimate that does not exceed its remaining coverage.
663
639
 
664
640
  Legacy aliases: `create-customer-invoice`, `create_customer_invoice`.
665
641