@go-labs-sg/bb 3.1.0 → 3.2.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.
@@ -2317,7 +2317,7 @@
2317
2317
  {
2318
2318
  "path": ["bill", "create"],
2319
2319
  "legacyAliases": ["create-bill", "create_bill"],
2320
- "summary": "Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.",
2320
+ "summary": "Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.",
2321
2321
  "globalOptions": [
2322
2322
  {
2323
2323
  "name": "--help",
@@ -2375,7 +2375,7 @@
2375
2375
  {
2376
2376
  "path": ["bill", "selection", "validate"],
2377
2377
  "legacyAliases": ["validate-bill-selection", "validate_bill_selection"],
2378
- "summary": "Validate the approved supplier and selected bill line items.",
2378
+ "summary": "Validate the approved supplier and selected bill line items. Supplier bills need approved quotation sources (quotationIds, legacy quotationId, or quotationAllocations with lineAmounts) for every line that is not quotation-exempt (Go Internal lines, or projects/budgets created before the quotation cutoff). With billId, lines already on the bill keep their stored sources unless new sources are supplied. Exemption is decided by the server, so there is no --quotation-exempt flag here. Amounts (amount, lineAmounts, quotationAllocations) are ex-GST dollars with at most 2 decimal places.",
2379
2379
  "globalOptions": [
2380
2380
  {
2381
2381
  "name": "--help",
@@ -2491,7 +2491,7 @@
2491
2491
  {
2492
2492
  "path": ["bill", "update"],
2493
2493
  "legacyAliases": ["update-bill", "update_bill"],
2494
- "summary": "Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.",
2494
+ "summary": "Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.",
2495
2495
  "globalOptions": [
2496
2496
  {
2497
2497
  "name": "--help",
@@ -10255,7 +10255,7 @@
10255
10255
  {
10256
10256
  "path": ["webhook", "delivery", "list"],
10257
10257
  "legacyAliases": ["list-webhook-deliveries", "list_webhook_deliveries"],
10258
- "summary": "List webhook deliveries.",
10258
+ "summary": "Admin-only: list webhook deliveries newest first. Returns { items, pageInfo }; follow pageInfo.nextCursor (or previousCursor with --direction backward). Cursors are opaque and filter-bound; raw delivery ids are rejected.",
10259
10259
  "globalOptions": [
10260
10260
  {
10261
10261
  "name": "--help",
@@ -10296,6 +10296,30 @@
10296
10296
  {
10297
10297
  "name": "--allow-financial-write",
10298
10298
  "description": "Allow financial-record changes in non-interactive use."
10299
+ },
10300
+ {
10301
+ "name": "--endpointId <id>",
10302
+ "description": "Only deliveries to this endpoint."
10303
+ },
10304
+ {
10305
+ "name": "--status <PENDING|SUCCEEDED|FAILED,...>",
10306
+ "description": "Comma-separated delivery statuses."
10307
+ },
10308
+ {
10309
+ "name": "--eventType <type>",
10310
+ "description": "Exact event type, e.g. bill.approved."
10311
+ },
10312
+ {
10313
+ "name": "--limit <n>",
10314
+ "description": "Rows per cursor page (1..100; default 20)."
10315
+ },
10316
+ {
10317
+ "name": "--cursor <token>",
10318
+ "description": "Opaque token from pageInfo.nextCursor or pageInfo.previousCursor; bound to the same filters."
10319
+ },
10320
+ {
10321
+ "name": "--direction <value>",
10322
+ "description": "forward or backward (default forward; backward requires cursor)."
10299
10323
  }
10300
10324
  ],
10301
10325
  "argumentMode": "legacy-passthrough",
@@ -396,7 +396,7 @@ Effects: state-change, email.
396
396
 
397
397
  ## `bb bill create`
398
398
 
399
- Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.
399
+ Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.
400
400
 
401
401
  Legacy aliases: `create-bill`, `create_bill`.
402
402
 
@@ -409,7 +409,7 @@ Payload fields (--payload JSON)
409
409
 
410
410
  ## `bb bill selection validate`
411
411
 
412
- Validate the approved supplier and selected bill line items.
412
+ Validate the approved supplier and selected bill line items. Supplier bills need approved quotation sources (quotationIds, legacy quotationId, or quotationAllocations with lineAmounts) for every line that is not quotation-exempt (Go Internal lines, or projects/budgets created before the quotation cutoff). With billId, lines already on the bill keep their stored sources unless new sources are supplied. Exemption is decided by the server, so there is no --quotation-exempt flag here. Amounts (amount, lineAmounts, quotationAllocations) are ex-GST dollars with at most 2 decimal places.
413
413
 
414
414
  Legacy aliases: `validate-bill-selection`, `validate_bill_selection`.
415
415
 
@@ -435,7 +435,7 @@ Payload fields (--payload JSON)
435
435
 
436
436
  ## `bb bill update`
437
437
 
438
- Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.
438
+ Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.
439
439
 
440
440
  Legacy aliases: `update-bill`, `update_bill`.
441
441
 
@@ -1657,7 +1657,7 @@ Effects: state-change.
1657
1657
 
1658
1658
  ## `bb webhook delivery list`
1659
1659
 
1660
- List webhook deliveries.
1660
+ Admin-only: list webhook deliveries newest first. Returns { items, pageInfo }; follow pageInfo.nextCursor (or previousCursor with --direction backward). Cursors are opaque and filter-bound; raw delivery ids are rejected.
1661
1661
 
1662
1662
  Legacy aliases: `list-webhook-deliveries`, `list_webhook_deliveries`.
1663
1663
 
package/dist/index.js CHANGED
@@ -7723,7 +7723,7 @@ var parseQuotationReferences = (input, commandName) => {
7723
7723
  const allocation = requireObject(raw, label);
7724
7724
  const amount = Number(allocation.amount);
7725
7725
  if (!Number.isFinite(amount) || amount < 0 || !Number.isInteger(amount * 100)) {
7726
- throw validationError(`${label}.amount must be a non-negative cent value.`);
7726
+ throw validationError(`${label}.amount must be a non-negative dollar amount (ex-GST) with at most 2 decimal places.`);
7727
7727
  }
7728
7728
  return {
7729
7729
  budgetItemId: requiredString(allocation.budgetItemId, `${label}.budgetItemId`),
@@ -7776,7 +7776,7 @@ var parseBillLineAmounts = (input, commandName) => {
7776
7776
  const line = requireObject(raw, label);
7777
7777
  const amount = Number(line.amount);
7778
7778
  if (!Number.isFinite(amount) || amount < 0 || !Number.isInteger(amount * 100)) {
7779
- throw validationError(`${label}.amount must be a non-negative cent value.`);
7779
+ throw validationError(`${label}.amount must be a non-negative dollar amount (ex-GST) with at most 2 decimal places.`);
7780
7780
  }
7781
7781
  return {
7782
7782
  budgetItemId: requiredString(line.budgetItemId, `${label}.budgetItemId`),
@@ -11473,6 +11473,8 @@ var summaryFor = (legacyTarget) => {
11473
11473
  return "List one cursor page of active item categories ({ items, pageInfo }; --limit/--cursor/--direction, optional --name/--sortBy/--sortDir). --page/--perPage are rejected.";
11474
11474
  if (legacyTarget === "count-item-categories")
11475
11475
  return "Count active item categories matching --name: { totalCount }.";
11476
+ if (legacyTarget === "list-webhook-deliveries")
11477
+ return "Admin-only: list webhook deliveries newest first. Returns { items, pageInfo }; follow pageInfo.nextCursor (or previousCursor with --direction backward). Cursors are opaque and filter-bound; raw delivery ids are rejected.";
11476
11478
  if (legacyTarget === "list-integration-operations")
11477
11479
  return "List one cursor page of integration operations, newest first ({ items, pageInfo }; --limit/--cursor/--direction). --page/--perPage are rejected. Admin only.";
11478
11480
  if (legacyTarget === "count-integration-operations")
@@ -11491,17 +11493,17 @@ var summaryFor = (legacyTarget) => {
11491
11493
  return "Get budget details. Omit --includeInactive for active budgets only; --includeInactive is an Admin-only historical read.";
11492
11494
  }
11493
11495
  if (legacyTarget === "create-bill") {
11494
- return "Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.";
11496
+ return "Create a bill or claim with an approved supplier. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. --draft-only guarantees DRAFT without email or external writes; otherwise unpaid creation skips email permission but keeps external-write permission.";
11495
11497
  }
11496
11498
  if (legacyTarget === "record-external-bill-payment")
11497
11499
  return "Record an already-made payment on an APPROVED bill or claim, with no email and no money transfer. Requires <billId> --paymentReference --paymentDate YYYY-MM-DD --paymentAccount <QBO account ID> [--paymentProof receipt.pdf]. Reuses settled QBO payment links or queues one dated payment from the selected account. Exact retries are safe; do not pay again while reconciliation is pending.";
11498
11500
  if (legacyTarget === "list-external-payment-accounts")
11499
11501
  return "List active QuickBooks bank and credit-card account IDs for recording external payments (admin only).";
11500
11502
  if (legacyTarget === "update-bill") {
11501
- return "Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.";
11503
+ return "Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. If the selected quotations cannot split the bill amount across every selected line (a line without a quoted amount that cannot be derived from the quotation total), pass lineAmounts; updates that keep the same amount and lines reuse the existing line amounts. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.";
11502
11504
  }
11503
11505
  if (legacyTarget === "validate-bill-selection") {
11504
- return "Validate the approved supplier and selected bill line items.";
11506
+ return "Validate the approved supplier and selected bill line items. Supplier bills need approved quotation sources (quotationIds, legacy quotationId, or quotationAllocations with lineAmounts) for every line that is not quotation-exempt (Go Internal lines, or projects/budgets created before the quotation cutoff). With billId, lines already on the bill keep their stored sources unless new sources are supplied. Exemption is decided by the server, so there is no --quotation-exempt flag here. Amounts (amount, lineAmounts, quotationAllocations) are ex-GST dollars with at most 2 decimal places.";
11505
11507
  }
11506
11508
  if (legacyTarget === "create-quotation") {
11507
11509
  return 'Create a quotation with an approved supplier using --payload JSON. Include projectId, budgetId, supplierId, budgetItemIds, amountWithoutGst, gstAmount, and one uploaded attachment in attachments. Multiple budget items require lineAmounts: [{"budgetItemId":"<first-id>","amount":750},{"budgetItemId":"<second-id>","amount":450}], covering every selected budget-item ID exactly once and summing to amountWithoutGst. Amounts exclude GST; use gstAmount: 0 for no GST. Example: amountWithoutGst: 1200 with line amounts 750 and 450.';
@@ -12490,7 +12492,32 @@ var registry2 = [
12490
12492
  legacyCommand("delete-webhook-endpoint", ["webhook", "endpoint", "delete"]),
12491
12493
  legacyCommand("rotate-webhook-secret", ["webhook", "secret", "rotate"]),
12492
12494
  legacyCommand("send-webhook-test-event", ["webhook", "endpoint", "test"]),
12493
- legacyCommand("list-webhook-deliveries", ["webhook", "delivery", "list"]),
12495
+ legacyCommand("list-webhook-deliveries", ["webhook", "delivery", "list"], [], [
12496
+ {
12497
+ name: "--endpointId <id>",
12498
+ description: "Only deliveries to this endpoint."
12499
+ },
12500
+ {
12501
+ name: "--status <PENDING|SUCCEEDED|FAILED,...>",
12502
+ description: "Comma-separated delivery statuses."
12503
+ },
12504
+ {
12505
+ name: "--eventType <type>",
12506
+ description: "Exact event type, e.g. bill.approved."
12507
+ },
12508
+ {
12509
+ name: "--limit <n>",
12510
+ description: "Rows per cursor page (1..100; default 20)."
12511
+ },
12512
+ {
12513
+ name: "--cursor <token>",
12514
+ description: "Opaque token from pageInfo.nextCursor or pageInfo.previousCursor; bound to the same filters."
12515
+ },
12516
+ {
12517
+ name: "--direction <value>",
12518
+ description: "forward or backward (default forward; backward requires cursor)."
12519
+ }
12520
+ ]),
12494
12521
  legacyCommand("get-webhook-delivery", ["webhook", "delivery", "get"]),
12495
12522
  legacyCommand("replay-webhook-delivery", ["webhook", "delivery", "replay"]),
12496
12523
  legacyCommand("list-inbound-sources", ["inbound", "source", "list"], [], [
@@ -13544,7 +13571,7 @@ Webhooks (admin)
13544
13571
  delete-webhook-endpoint <endpointId>
13545
13572
  rotate-webhook-secret <endpointId> [--previousSecretTtlHours <0-168>] (prints the new secret once)
13546
13573
  send-webhook-test-event <endpointId>
13547
- list-webhook-deliveries [--endpointId] [--status PENDING|SUCCEEDED|FAILED] [--eventType] [--cursor] [--limit]
13574
+ list-webhook-deliveries [--endpointId] [--status <PENDING|SUCCEEDED|FAILED,...>] [--eventType] [--limit 1-100] [--cursor <token>] [--direction forward|backward] (newest first; prints items + pageInfo)
13548
13575
  get-webhook-delivery <deliveryId> (attempts with response codes)
13549
13576
  replay-webhook-delivery <deliveryId> (same eventId, new attempt chain)
13550
13577
 
@@ -15922,14 +15949,22 @@ Waiting for approval\u2026
15922
15949
  break;
15923
15950
  }
15924
15951
  case "list-webhook-deliveries": {
15925
- const status = getFlag(flags, "status");
15926
- if (status && status !== "PENDING" && status !== "SUCCEEDED" && status !== "FAILED")
15927
- throw new Error("--status must be PENDING, SUCCEEDED or FAILED");
15952
+ const statuses = (getFlag(flags, "status") ?? "").split(",").map((value) => value.trim()).filter(Boolean);
15953
+ for (const status of statuses)
15954
+ if (status !== "PENDING" && status !== "SUCCEEDED" && status !== "FAILED")
15955
+ throw new Error("--status must be PENDING, SUCCEEDED or FAILED (comma-separated)");
15956
+ const cursor = getFlag(flags, "cursor");
15957
+ const direction = parseProjectDirection(getFlag(flags, "direction"));
15958
+ if (direction === "backward" && !cursor)
15959
+ throw new Error("--direction backward requires --cursor <token>.");
15928
15960
  await listWebhookDeliveries({
15929
15961
  endpointId: getFlag(flags, "endpointId"),
15930
- status,
15962
+ ...statuses.length ? {
15963
+ status: statuses
15964
+ } : {},
15931
15965
  eventType: getFlag(flags, "eventType"),
15932
- cursor: getFlag(flags, "cursor"),
15966
+ cursor,
15967
+ direction,
15933
15968
  limit: parsePositiveIntFlag(getFlag(flags, "limit"), "--limit")
15934
15969
  });
15935
15970
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/bb",
3
- "version": "3.1.0",
3
+ "version": "3.2.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",