@go-labs-sg/bb 2.47.0 → 2.48.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.
Files changed (3) hide show
  1. package/README.md +15 -6
  2. package/dist/index.js +28 -28
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -501,7 +501,11 @@ bb budget version list <budgetId> --all
501
501
  - `--all` explicitly collects all visible history through sequential bounded requests. It cannot be combined with `--cursor`; `--limit` controls each request's size. It can still be expensive and retains the complete result in memory. A failed page aborts without emitting a successful partial export.
502
502
  - Pages preserve newest-first `createdAt`/`id` ordering, role visibility, and creator/version-group metadata. They are not a point-in-time database snapshot; versions added after traversal starts require a fresh first-page read, and concurrent changes to visibility can affect traversal.
503
503
 
504
- The backend must expose `budgetVersion.getBudgetVersionsPage`. The legacy unbounded tRPC `getBudgetVersions` remains available but deprecated for external compatibility; unknown external clients are not silently capped. Removing that endpoint requires a separate usage/compatibility review. This change does not publish the CLI, deploy the backend, delete audit snapshots, or establish measured RU savings.
504
+ The canonical backend procedure is `budgetVersion.getBudgetVersions`. It now accepts `{ budgetId, limit?, cursor? }` and returns `{ versions, nextCursor }`, with a default page size of 20 and maximum of 50. The former budgetId-only input remains valid, but returns the first page—not a complete-history array. **This response-shape and completeness change is breaking despite keeping the route name.** Older installed CLI builds and external scripts must consume `versions` and explicitly continue through `nextCursor`; otherwise they may fail or mistake partial history for a complete export. Deprecated MCP builds may also be incompatible, but they must not be updated or used as a rollout gate. Current CLI aliases `get-budget-versions` and `get_budget_versions` remain supported.
505
+
506
+ For direct tRPC clients, call `getBudgetVersions.query({ budgetId, limit: 20, cursor })`, consume `versions`, and request the next page only when `nextCursor` is present. The intermediate `getBudgetVersionsPage` procedure is removed; migrate callers of that name to `getBudgetVersions` rather than retrying `NOT_FOUND`. A complete export must explicitly walk every page, abort on a failed page or repeated cursor, and emit success only after reaching the end; `bb budget version list <budgetId> --all` implements that traversal. Do not treat a first page as complete history. The existing missing/deleted-cursor behavior and non-snapshot traversal are unchanged; concurrent deletions or visibility changes can require restarting an export.
507
+
508
+ Coordinate the backend and maintained client rollout: publish/use this CLI only against a backend with the paginated `getBudgetVersions` contract; an older backend returns an array under that same name. MCP is deprecated and frozen, so do not update or publish it. Existing builds that call `getBudgetVersionsPage` must also migrate before that route is removed, including cached web bundles. The residual requester is not yet attributed: server timing logs prove route usage but do not identify its client or installed version. Reusing the route name bounds its history result; it does not prove complete-history consumers migrated, that a periodic schedule stopped, or that measured RU savings occurred. This source change does not publish clients, deploy the backend, delete audit snapshots or change indexes.
505
509
 
506
510
  ### Link an existing QuickBooks invoice
507
511
 
@@ -602,17 +606,22 @@ A `.env` file in the **current working directory** is loaded automatically for a
602
606
 
603
607
  ## Developing in this repo
604
608
 
605
- From the monorepo root (after `bun install`):
609
+ Follow the [development workflow](../../../docs/development-workflow.md#required-cli-coverage). App/API changes affecting `bb` must include CLI contracts, registry/help/docs and verification in the same change; do not update deprecated MCP.
610
+
611
+ From the monorepo root, after isolated worktree setup and client generation:
606
612
 
607
613
  ```bash
608
- export BB_API_KEY=...
609
- bun run packages/budget-builder/cli/src/index.ts budget list
614
+ bun --filter @go-labs-sg/bb typecheck
615
+ bun --filter @go-labs-sg/bb build
616
+ bun run packages/budget-builder/cli/src/index.ts help
610
617
  ```
611
618
 
619
+ Use approved browser authorization or an existing automation API key for commands that access data. Help/build examples do not authorize production reads, mutations, email or financial writes.
620
+
612
621
  Or from `packages/budget-builder/cli`:
613
622
 
614
623
  ```bash
615
- bun run build # emit dist/ via tsc
624
+ bun run build # generate command artifacts, then bundle dist/index.js with Bun
616
625
  bun run typecheck # tsc --noEmit
617
626
  bun run src/index.ts budget list
618
627
  ```
@@ -624,7 +633,7 @@ bun run src/index.ts budget list
624
633
 
625
634
  ### Publish
626
635
 
627
- Build the package first, then create its publishable archive with Bun:
636
+ Only prepare publication when authorized; building or packing is not permission to publish. From `packages/budget-builder/cli`, build the package first, then create its publishable archive with Bun:
628
637
 
629
638
  ```bash
630
639
  bun run build
package/dist/index.js CHANGED
@@ -35,16 +35,16 @@ var __toESM = (mod, isNodeMode, target) => {
35
35
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
36
36
  var __require = import.meta.require;
37
37
 
38
- // ../../../node_modules/.bun/dotenv@18.0.5/node_modules/dotenv/dist/index.cjs
38
+ // ../../../node_modules/.bun/dotenv@18.0.6/node_modules/dotenv/dist/index.cjs
39
39
  var require_dist = __commonJS(function(exports, module) {
40
- var I = (e, o) => () => {
40
+ var S = (e, o) => () => {
41
41
  try {
42
42
  return o || e((o = { exports: {} }).exports, o), o.exports;
43
43
  } catch (t) {
44
44
  throw o = 0, t;
45
45
  }
46
46
  };
47
- var S = I((xe, U) => {
47
+ var j = S((xe, U) => {
48
48
  function G(e) {
49
49
  return typeof e == "string" ? !["false", "0", "no", "off", ""].includes(e.toLowerCase()) : !!e;
50
50
  }
@@ -58,8 +58,8 @@ var require_dist = __commonJS(function(exports, module) {
58
58
  }
59
59
  U.exports = { parseBoolean: G, optionsFromEnv: X };
60
60
  });
61
- var N = I((ye, x) => {
62
- var Y = __require("fs"), j = __require("path"), z = __require("os"), { URL: Z, fileURLToPath: ee } = __require("url"), { parseBoolean: k, optionsFromEnv: B } = S(), te = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg, b = new Uint8Array(256);
61
+ var N = S((ye, x) => {
62
+ var Y = __require("fs"), k = __require("path"), z = __require("os"), { URL: Z, fileURLToPath: ee } = __require("url"), { parseBoolean: $, optionsFromEnv: B } = j(), te = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg, b = new Uint8Array(256);
63
63
  for (let e = 48;e <= 57; e++)
64
64
  b[e] = 1;
65
65
  for (let e = 65;e <= 90; e++)
@@ -185,7 +185,7 @@ var require_dist = __commonJS(function(exports, module) {
185
185
  return o;
186
186
  }
187
187
  function ne(e, o) {
188
- return o && k(o.fast) ? oe(e) : re(e);
188
+ return o && $(o.fast) ? oe(e) : re(e);
189
189
  }
190
190
  function T(e) {
191
191
  console.log(`\u2506 ${e}`);
@@ -194,16 +194,16 @@ var require_dist = __commonJS(function(exports, module) {
194
194
  console.error(`\u25C7 ${e}`);
195
195
  }
196
196
  function V(e) {
197
- return e[0] === "~" ? j.join(z.homedir(), e.slice(1)) : e;
197
+ return e[0] === "~" ? k.join(z.homedir(), e.slice(1)) : e;
198
198
  }
199
199
  function ie(e = {}) {
200
200
  return { ...B(), ...e };
201
201
  }
202
202
  function ce(e) {
203
203
  e = ie(e);
204
- let o = j.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
204
+ let o = k.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
205
205
  e && e.processEnv != null && (n = e.processEnv);
206
- let r = k(e && e.debug);
206
+ let r = $(e && e.debug);
207
207
  e && e.encoding ? t = e.encoding : r && T("no encoding is specified (UTF-8 is used by default)");
208
208
  let s = [o];
209
209
  if (e && e.path)
@@ -222,12 +222,12 @@ var require_dist = __commonJS(function(exports, module) {
222
222
  } catch (a) {
223
223
  r && T(`failed to load ${c} ${a.message}`), i = a;
224
224
  }
225
- let p = A.populate(n, l, e), f = k(Object.prototype.hasOwnProperty.call(e, "quiet") ? e.quiet : B(n).quiet);
225
+ let p = A.populate(n, l, e), f = $(Object.prototype.hasOwnProperty.call(e, "quiet") ? e.quiet : B(n).quiet);
226
226
  if (r || !f) {
227
227
  let c = Object.keys(p).length, a = [];
228
228
  for (let g of s)
229
229
  try {
230
- let h = j.relative(process.cwd(), g instanceof Z ? ee(g) : g);
230
+ let h = k.relative(process.cwd(), g instanceof Z ? ee(g) : g);
231
231
  a.push(h);
232
232
  } catch (h) {
233
233
  r && T(`failed to load ${g} ${h.message}`), i = h;
@@ -240,7 +240,7 @@ var require_dist = __commonJS(function(exports, module) {
240
240
  return A.configDotenv(e);
241
241
  }
242
242
  function le(e, o, t = {}) {
243
- let n = !!(t && t.debug), r = !!(t && t.override), s = {};
243
+ let n = $(t && t.debug), r = $(t && t.override), s = {};
244
244
  if (e === null || typeof e != "object" || o === null || typeof o != "object") {
245
245
  let i = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
246
246
  throw i.code = "OBJECT_REQUIRED", i;
@@ -256,7 +256,7 @@ var require_dist = __commonJS(function(exports, module) {
256
256
  x.exports.populate = A.populate;
257
257
  x.exports = A;
258
258
  });
259
- var M = I((Te, W) => {
259
+ var M = S((Te, W) => {
260
260
  var _ = __require("child_process"), fe = __require("fs"), L = __require("path");
261
261
  function ue(e) {
262
262
  let o = ['"'], t = 0;
@@ -309,9 +309,9 @@ var require_dist = __commonJS(function(exports, module) {
309
309
  }
310
310
  W.exports = pe;
311
311
  });
312
- var K = I(($e, F) => {
313
- var he = __require("fs"), ge = __require("os"), Q = __require("path"), me = __require("child_process"), ve = M(), R = N(), { optionsFromEnv: Ce } = S();
314
- function $() {
312
+ var K = S(($e, F) => {
313
+ var he = __require("fs"), ge = __require("os"), Q = __require("path"), me = __require("child_process"), ve = M(), R = N(), { optionsFromEnv: Ce } = j();
314
+ function D() {
315
315
  console.log(["Usage: dotenv run [--help] [-q|--quiet] [--debug] [--override] [--fast] [-f|--file <paths>] [--] <command> [args...]", "", "Run a command with environment variables from a .env file.", "Place dotenv options before the command; all following arguments go to the command.", "", "Options:", " -f, --file <paths> .env paths, comma-separated or repeated (default: .env)", " -q, --quiet suppress the injected env message", " --debug enable debug logging", " --override override existing environment variables", " --fast use the faster character-scanner parser", "", "Environment variables (DOTENV_CONFIG_* names remain as fallbacks):", " DOTENV_PATH, DOTENV_ENCODING, DOTENV_QUIET,", " DOTENV_DEBUG, DOTENV_OVERRIDE,", " DOTENV_FAST"].join(`
316
316
  `));
317
317
  }
@@ -383,24 +383,24 @@ var require_dist = __commonJS(function(exports, module) {
383
383
  function J(e) {
384
384
  let o = e[0];
385
385
  if (o === "--help" || o === "-h") {
386
- $();
386
+ D();
387
387
  return;
388
388
  }
389
389
  if (o !== "run") {
390
- $(), process.exitCode = 1;
390
+ D(), process.exitCode = 1;
391
391
  return;
392
392
  }
393
393
  let t = we(e.slice(1));
394
394
  if (t.help) {
395
- $();
395
+ D();
396
396
  return;
397
397
  }
398
398
  if (t.error) {
399
- console.error(`dotenv: ${t.error}`), $(), process.exitCode = 1;
399
+ console.error(`dotenv: ${t.error}`), D(), process.exitCode = 1;
400
400
  return;
401
401
  }
402
402
  if (t.command.length === 0) {
403
- $(), process.exitCode = 1;
403
+ D(), process.exitCode = 1;
404
404
  return;
405
405
  }
406
406
  let n = Ee(t);
@@ -456,13 +456,13 @@ var require_dist = __commonJS(function(exports, module) {
456
456
  F.exports = J;
457
457
  F === __require.main && J(process.argv.slice(2));
458
458
  });
459
- var D = N();
459
+ var I = N();
460
460
  var Oe = K();
461
- module.exports = D;
462
- module.exports.config = D.config;
463
- module.exports.configDotenv = D.configDotenv;
464
- module.exports.parse = D.parse;
465
- module.exports.populate = D.populate;
461
+ module.exports = I;
462
+ module.exports.config = I.config;
463
+ module.exports.configDotenv = I.configDotenv;
464
+ module.exports.parse = I.parse;
465
+ module.exports.populate = I.populate;
466
466
  });
467
467
 
468
468
  // src/load-env.ts
@@ -9576,7 +9576,7 @@ var getBudgetVersions = async (budgetId, options = {}) => {
9576
9576
  const seenCursors = new Set;
9577
9577
  let cursor = options.cursor;
9578
9578
  do {
9579
- const page = await api2.budgetVersion.getBudgetVersionsPage.query({
9579
+ const page = await api2.budgetVersion.getBudgetVersions.query({
9580
9580
  budgetId,
9581
9581
  limit: options.limit,
9582
9582
  cursor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/bb",
3
- "version": "2.47.0",
3
+ "version": "2.48.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",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "@trpc/client": "^11.19.0",
23
- "dotenv": "^18.0.1",
23
+ "dotenv": "^18.0.6",
24
24
  "mime-types": "^3.0.2",
25
25
  "superjson": "^2.2.6"
26
26
  },