@go-labs-sg/bb 2.44.0 → 2.45.1

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
@@ -508,6 +508,8 @@ Project and budget query payloads keep the Asana identities explicit: `asanaTask
508
508
 
509
509
  Bill, claim, and quotation mutations accept only suppliers whose approval status is `APPROVED`. An active supplier that is `PENDING_APPROVAL`, `REJECTED`, or `SUPERSEDED` must be approved before it can be used.
510
510
 
511
+ Admin/Lead users can run `bb supplier approve <supplierId>` to directly re-approve a `REJECTED` supplier even when no pending approval request exists. This appends a new approval record and activity entry with the current responder/time, retains earlier approval and rejection history unchanged, and synchronizes QuickBooks; it does not send a requester reply email. Non-interactive direct re-approval requires `--allow-state-change --allow-external-write`, without `--allow-email`. An archived supplier remains archived and also needs Admin reactivation (`bb supplier reactivate --ids <supplierId>`) before new use. Reactivating alone does not change approval status. For a pending supplier, the command still resolves the current user's assigned request and queues the existing reply email.
512
+
511
513
  | Area | Legacy handler labels (reference only; non-exhaustive) |
512
514
  | --- | --- |
513
515
  | **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`) |
@@ -4795,7 +4795,7 @@
4795
4795
  {
4796
4796
  "path": ["supplier", "approve"],
4797
4797
  "legacyAliases": ["approve-supplier", "approve_supplier"],
4798
- "summary": "Approve Supplier.",
4798
+ "summary": "Approve a pending supplier request and send a requester reply email, or directly re-approve a rejected supplier as Admin/Lead without a pending request or email. QuickBooks is synchronized; archived suppliers remain archived. Argument: <supplierId>.",
4799
4799
  "globalOptions": [
4800
4800
  {
4801
4801
  "name": "--help",
@@ -833,7 +833,7 @@ Effects: state-change, email.
833
833
 
834
834
  ## `bb supplier approve`
835
835
 
836
- Approve Supplier.
836
+ Approve a pending supplier request and send a requester reply email, or directly re-approve a rejected supplier as Admin/Lead without a pending request or email. QuickBooks is synchronized; archived suppliers remain archived. Argument: <supplierId>.
837
837
 
838
838
  Legacy aliases: `approve-supplier`, `approve_supplier`.
839
839
 
package/dist/index.js CHANGED
@@ -35,46 +35,46 @@ 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.1/node_modules/dotenv/dist/index.cjs
38
+ // ../../../node_modules/.bun/dotenv@18.0.5/node_modules/dotenv/dist/index.cjs
39
39
  var require_dist = __commonJS(function(exports, module) {
40
- var O = (e, o) => () => {
40
+ var I = (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 q = O((Ce, j) => {
48
- function I(e) {
47
+ var S = I((xe, U) => {
48
+ function G(e) {
49
49
  return typeof e == "string" ? !["false", "0", "no", "off", ""].includes(e.toLowerCase()) : !!e;
50
50
  }
51
- function B() {
52
- let e = {};
53
- for (let o of ["ENCODING", "PATH", "QUIET", "DEBUG", "OVERRIDE", "FAST"]) {
54
- let t = process.env[`DOTENV_${o}`] != null ? process.env[`DOTENV_${o}`] : process.env[`DOTENV_CONFIG_${o}`];
55
- t != null && (e[o.toLowerCase()] = o === "ENCODING" || o === "PATH" ? t : I(t));
51
+ function X(e = process.env) {
52
+ let o = {};
53
+ for (let t of ["ENCODING", "PATH", "QUIET", "DEBUG", "OVERRIDE", "FAST"]) {
54
+ let n = e[`DOTENV_${t}`] != null ? e[`DOTENV_${t}`] : e[`DOTENV_CONFIG_${t}`];
55
+ n != null && (o[t.toLowerCase()] = t === "ENCODING" || t === "PATH" ? n : G(n));
56
56
  }
57
- return e;
57
+ return o;
58
58
  }
59
- j.exports = { parseBoolean: I, optionsFromEnv: B };
59
+ U.exports = { parseBoolean: G, optionsFromEnv: X };
60
60
  });
61
- var y = O((we, C) => {
62
- var H = __require("fs"), x = __require("path"), L = __require("os"), { URL: M, fileURLToPath: W } = __require("url"), { parseBoolean: T, optionsFromEnv: Q } = q(), J = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg, v = new Uint8Array(256);
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);
63
63
  for (let e = 48;e <= 57; e++)
64
- v[e] = 1;
64
+ b[e] = 1;
65
65
  for (let e = 65;e <= 90; e++)
66
- v[e] = 1;
66
+ b[e] = 1;
67
67
  for (let e = 97;e <= 122; e++)
68
- v[e] = 1;
69
- v[45] = 1;
70
- v[46] = 1;
71
- v[95] = 1;
72
- function K(e) {
68
+ b[e] = 1;
69
+ b[45] = 1;
70
+ b[46] = 1;
71
+ b[95] = 1;
72
+ function re(e) {
73
73
  let o = {}, t = e.toString();
74
74
  t = t.replace(/\r\n?/mg, `
75
75
  `);
76
76
  let n;
77
- for (;(n = J.exec(t)) != null; ) {
77
+ for (;(n = te.exec(t)) != null; ) {
78
78
  let r = n[1], s = n[2] || "";
79
79
  s = s.trim();
80
80
  let i = s[0];
@@ -83,192 +83,182 @@ var require_dist = __commonJS(function(exports, module) {
83
83
  }
84
84
  return o;
85
85
  }
86
- function X(e) {
86
+ function w(e) {
87
+ return e <= 32 ? e === 32 || e >= 9 && e <= 13 : e >= 160 && (e === 160 || e === 5760 || e >= 8192 && e <= 8202 || e === 8232 || e === 8233 || e === 8239 || e === 8287 || e === 12288 || e === 65279);
88
+ }
89
+ function O(e) {
90
+ return e === 10 || e === 8232 || e === 8233;
91
+ }
92
+ function oe(e) {
87
93
  let o = {}, t = typeof e == "string" ? e : e.toString();
88
94
  t.indexOf("\r") !== -1 && (t = t.replace(/\r\n?/g, `
89
95
  `));
90
96
  let n = t.length, r = 0;
91
97
  for (;r < n; ) {
92
98
  let s = t.charCodeAt(r);
93
- for (;r < n && (s === 32 || s === 9 || s === 10 || s === 65279); )
99
+ for (;r < n && w(s); )
94
100
  r++, s = t.charCodeAt(r);
95
101
  if (r >= n)
96
102
  break;
97
103
  if (s === 35) {
98
- for (;r < n && t.charCodeAt(r) !== 10; )
104
+ for (;r < n && !O(t.charCodeAt(r)); )
99
105
  r++;
100
106
  continue;
101
107
  }
108
+ let i = -1;
102
109
  if (s === 101 && r + 6 < n && t.charCodeAt(r + 1) === 120 && t.charCodeAt(r + 2) === 112 && t.charCodeAt(r + 3) === 111 && t.charCodeAt(r + 4) === 114 && t.charCodeAt(r + 5) === 116) {
103
- let f = t.charCodeAt(r + 6);
104
- if (f === 32 || f === 9)
105
- for (r += 7;r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
106
- r++;
107
- else
110
+ let v = t.charCodeAt(r + 6);
111
+ if (w(v)) {
112
+ let u = r + 7;
113
+ for (;u < n && w(t.charCodeAt(u)); )
114
+ u++;
115
+ b[t.charCodeAt(u)] && (i = r + 6, r = u);
116
+ } else
108
117
  s = t.charCodeAt(r);
109
118
  }
110
- let i = r, l = 0;
111
- for (;r < n && (l = t.charCodeAt(r), v[l]); )
119
+ let l = r, d = 0;
120
+ for (;r < n && (d = t.charCodeAt(r), b[d]); )
112
121
  r++;
113
- if (r === i) {
114
- for (;r < n && t.charCodeAt(r) !== 10; )
122
+ if (r === l) {
123
+ for (;r < n && !O(t.charCodeAt(r)); )
115
124
  r++;
116
125
  continue;
117
126
  }
118
- let h = t.slice(i, r);
119
- if (r >= n && (l = 0), l === 32 || l === 9)
127
+ let p = t.slice(l, r), f = r;
128
+ if (r >= n && (d = 0), w(d))
120
129
  do
121
- r++, l = r < n ? t.charCodeAt(r) : 0;
122
- while (l === 32 || l === 9);
123
- if (l === 61)
124
- r++;
125
- else if (l === 58 && r + 1 < n && (t.charCodeAt(r + 1) === 32 || t.charCodeAt(r + 1) === 9))
130
+ r++, d = r < n ? t.charCodeAt(r) : 0;
131
+ while (w(d));
132
+ if (d === 61)
126
133
  r++;
134
+ else if (d === 58 && r === f && r + 1 < n && w(t.charCodeAt(r + 1)))
135
+ r += 2;
127
136
  else {
128
- for (;r < n && t.charCodeAt(r) !== 10; )
137
+ for (r = i === -1 ? f : i;r < n && !O(t.charCodeAt(r)); )
129
138
  r++;
130
139
  continue;
131
140
  }
132
- for (;r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
133
- r++;
134
- let u;
135
- if (s = r < n ? t.charCodeAt(r) : 0, s === 39 || s === 34 || s === 96) {
136
- let f = s, c = r + 1, a = c;
137
- for (;a < n; ) {
138
- let d = t.charCodeAt(a);
139
- if (d === 92 && a + 1 < n) {
140
- let p = t.charCodeAt(a + 1);
141
- if (p === f || p === 92) {
142
- a += 2;
143
- continue;
144
- }
145
- }
146
- if (d === f)
141
+ let c = r, a = r;
142
+ for (;a < n && w(t.charCodeAt(a)); )
143
+ a++;
144
+ let g = t.charCodeAt(a), h, y = false;
145
+ if (g === 39 || g === 34 || g === 96) {
146
+ let v = t[a], u = t.indexOf(v, a + 1), m = -1, C = -1;
147
+ for (;u !== -1; ) {
148
+ let q = t.charCodeAt(u - 1) === 92, E = u + 1;
149
+ for (;E < n && !O(t.charCodeAt(E)) && w(t.charCodeAt(E)); )
150
+ E++;
151
+ if ((E === n || O(t.charCodeAt(E)) || t.charCodeAt(E) === 35) && (m = u, C = E), !q)
147
152
  break;
148
- a++;
153
+ u = t.indexOf(v, u + 1);
149
154
  }
150
- if (a >= n) {
151
- let d = r, p = r;
152
- for (;p < n; ) {
153
- let w = t.charCodeAt(p);
154
- if (w === 35 || w === 10)
155
- break;
156
- p++;
157
- }
158
- let m = p;
159
- for (;m > d; ) {
160
- let w = t.charCodeAt(m - 1);
161
- if (w === 32 || w === 9)
162
- m--;
163
- else
164
- break;
165
- }
166
- if (u = t.slice(d, m), r = p, r < n && t.charCodeAt(r) === 35)
167
- for (;r < n && t.charCodeAt(r) !== 10; )
168
- r++;
169
- } else {
170
- for (u = t.slice(c, a), r = a + 1, f === 34 && u.indexOf("\\") !== -1 && (u = u.replace(/\\n/g, `
171
- `).replace(/\\r/g, "\r"));r < n && ((s = t.charCodeAt(r)) === 32 || s === 9); )
172
- r++;
173
- if (r < n && t.charCodeAt(r) === 35)
174
- for (;r < n && t.charCodeAt(r) !== 10; )
155
+ if (m !== -1) {
156
+ if (h = t.slice(a + 1, m), r = C, t.charCodeAt(r) === 35)
157
+ for (;r < n && !O(t.charCodeAt(r)); )
175
158
  r++;
159
+ y = true;
176
160
  }
177
- } else {
178
- let f = r, c = t.indexOf(`
179
- `, r);
180
- c === -1 && (c = n);
181
- let a = t.indexOf("#", r);
182
- (a === -1 || a > c) && (a = c);
183
- let d = a;
184
- for (;d > f; ) {
185
- let p = t.charCodeAt(d - 1);
186
- if (p === 32 || p === 9)
187
- d--;
188
- else
189
- break;
190
- }
191
- u = f === d ? "" : t.slice(f, d), r = a === c ? a : c;
192
161
  }
193
- o[h] = u;
162
+ if (!y) {
163
+ let v = t.indexOf(`
164
+ `, c);
165
+ v === -1 && (v = n);
166
+ let u;
167
+ if (n < 4096)
168
+ u = t.indexOf("#", c), (u === -1 || u > v) && (u = v);
169
+ else
170
+ for (u = c;u < v && t.charCodeAt(u) !== 35; )
171
+ u++;
172
+ let m = c, C = u;
173
+ for (;m < C && w(t.charCodeAt(m)); )
174
+ m++;
175
+ for (;C > m && w(t.charCodeAt(C - 1)); )
176
+ C--;
177
+ let q = t.charCodeAt(m);
178
+ if (C - m >= 2 && (q === 39 || q === 34 || q === 96) && t.charCodeAt(C - 1) === q ? h = t.slice(m + 1, C - 1) : h = t.slice(m, C), r = u, u < v)
179
+ for (;r < n && !O(t.charCodeAt(r)); )
180
+ r++;
181
+ }
182
+ g === 34 && (y || a < r) && h.indexOf("\\") !== -1 && (h = h.replace(/\\n/g, `
183
+ `).replace(/\\r/g, "\r")), o[p] = h;
194
184
  }
195
185
  return o;
196
186
  }
197
- function Y(e, o) {
198
- return o && T(o.fast) ? X(e) : K(e);
187
+ function ne(e, o) {
188
+ return o && k(o.fast) ? oe(e) : re(e);
199
189
  }
200
- function b(e) {
190
+ function T(e) {
201
191
  console.log(`\u2506 ${e}`);
202
192
  }
203
- function z(e) {
193
+ function se(e) {
204
194
  console.error(`\u25C7 ${e}`);
205
195
  }
206
- function N(e) {
207
- return e[0] === "~" ? x.join(L.homedir(), e.slice(1)) : e;
196
+ function V(e) {
197
+ return e[0] === "~" ? j.join(z.homedir(), e.slice(1)) : e;
208
198
  }
209
- function Z(e = {}) {
210
- return { ...Q(), ...e };
199
+ function ie(e = {}) {
200
+ return { ...B(), ...e };
211
201
  }
212
- function ee(e) {
213
- e = Z(e);
214
- let o = x.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
202
+ function ce(e) {
203
+ e = ie(e);
204
+ let o = j.resolve(process.cwd(), ".env"), t = "utf8", n = process.env;
215
205
  e && e.processEnv != null && (n = e.processEnv);
216
- let r = T(e && e.debug), s = T(e && e.quiet);
217
- e && e.encoding ? t = e.encoding : r && b("no encoding is specified (UTF-8 is used by default)");
218
- let i = [o];
206
+ let r = k(e && e.debug);
207
+ e && e.encoding ? t = e.encoding : r && T("no encoding is specified (UTF-8 is used by default)");
208
+ let s = [o];
219
209
  if (e && e.path)
220
210
  if (!Array.isArray(e.path))
221
- i = [N(e.path)];
211
+ s = [V(e.path)];
222
212
  else {
223
- i = [];
213
+ s = [];
224
214
  for (let c of e.path)
225
- i.push(N(c));
215
+ s.push(V(c));
226
216
  }
227
- let l, h = {}, u = { fast: e.fast };
228
- for (let c of i)
217
+ let i, l = {}, d = { fast: e.fast };
218
+ for (let c of s)
229
219
  try {
230
- let a = g.parse(H.readFileSync(c, { encoding: t }), u);
231
- g.populate(h, a, e);
220
+ let a = A.parse(Y.readFileSync(c, { encoding: t }), d);
221
+ A.populate(l, a, e);
232
222
  } catch (a) {
233
- r && b(`failed to load ${c} ${a.message}`), l = a;
223
+ r && T(`failed to load ${c} ${a.message}`), i = a;
234
224
  }
235
- let f = g.populate(n, h, e);
236
- if (r || !s) {
237
- let c = Object.keys(f).length, a = [];
238
- for (let d of i)
225
+ let p = A.populate(n, l, e), f = k(Object.prototype.hasOwnProperty.call(e, "quiet") ? e.quiet : B(n).quiet);
226
+ if (r || !f) {
227
+ let c = Object.keys(p).length, a = [];
228
+ for (let g of s)
239
229
  try {
240
- let p = x.relative(process.cwd(), d instanceof M ? W(d) : d);
241
- a.push(p);
242
- } catch (p) {
243
- r && b(`failed to load ${d} ${p.message}`), l = p;
230
+ let h = j.relative(process.cwd(), g instanceof Z ? ee(g) : g);
231
+ a.push(h);
232
+ } catch (h) {
233
+ r && T(`failed to load ${g} ${h.message}`), i = h;
244
234
  }
245
- z(`injected env (${c}) from ${a.join(",")}`);
235
+ se(`injected env (${c}) from ${a.join(",")}`);
246
236
  }
247
- return l ? { parsed: h, error: l } : { parsed: h };
237
+ return i ? { parsed: l, error: i } : { parsed: l };
248
238
  }
249
- function te(e) {
250
- return g.configDotenv(e);
239
+ function ae(e) {
240
+ return A.configDotenv(e);
251
241
  }
252
- function re(e, o, t = {}) {
242
+ function le(e, o, t = {}) {
253
243
  let n = !!(t && t.debug), r = !!(t && t.override), s = {};
254
244
  if (e === null || typeof e != "object" || o === null || typeof o != "object") {
255
245
  let i = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
256
246
  throw i.code = "OBJECT_REQUIRED", i;
257
247
  }
258
248
  for (let i of Object.keys(o))
259
- Object.prototype.hasOwnProperty.call(e, i) ? (r === true && (e[i] = o[i], s[i] = o[i]), n && b(r === true ? `"${i}" is already defined and WAS overwritten` : `"${i}" is already defined and was NOT overwritten`)) : (e[i] = o[i], s[i] = o[i]);
249
+ Object.prototype.hasOwnProperty.call(e, i) ? (r === true && (e[i] = o[i], s[i] = o[i]), n && T(r === true ? `"${i}" is already defined and WAS overwritten` : `"${i}" is already defined and was NOT overwritten`)) : (e[i] = o[i], s[i] = o[i]);
260
250
  return s;
261
251
  }
262
- var g = { configDotenv: ee, config: te, parse: Y, populate: re };
263
- C.exports.configDotenv = g.configDotenv;
264
- C.exports.config = g.config;
265
- C.exports.parse = g.parse;
266
- C.exports.populate = g.populate;
267
- C.exports = g;
252
+ var A = { configDotenv: ce, config: ae, parse: ne, populate: le };
253
+ x.exports.configDotenv = A.configDotenv;
254
+ x.exports.config = A.config;
255
+ x.exports.parse = A.parse;
256
+ x.exports.populate = A.populate;
257
+ x.exports = A;
268
258
  });
269
- var F = O((be, R) => {
270
- var $ = __require("child_process"), oe = __require("fs"), P = __require("path");
271
- function ne(e) {
259
+ var M = I((Te, W) => {
260
+ var _ = __require("child_process"), fe = __require("fs"), L = __require("path");
261
+ function ue(e) {
272
262
  let o = ['"'], t = 0;
273
263
  for (let n of e) {
274
264
  if (n === "\\") {
@@ -279,7 +269,7 @@ var require_dist = __commonJS(function(exports, module) {
279
269
  }
280
270
  return o.push("\\".repeat(t * 2), '"'), o.join("");
281
271
  }
282
- function _(e, o = 1) {
272
+ function H(e, o = 1) {
283
273
  for (let t = 0;t < o; t++) {
284
274
  let n = [];
285
275
  for (let r of e) {
@@ -290,47 +280,47 @@ var require_dist = __commonJS(function(exports, module) {
290
280
  }
291
281
  return e;
292
282
  }
293
- function D(e, o) {
283
+ function P(e, o) {
294
284
  let t = Object.keys(e).reverse().find((n) => n.toUpperCase() === o);
295
285
  return t === undefined ? undefined : e[t];
296
286
  }
297
- function se(e, o, t) {
298
- let n = (D(o, "PATHEXT") || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean), s = n.some((l) => e.toLowerCase().endsWith(l.toLowerCase())) ? ["", ...n] : [...n, ""], i = /[\\/]/.test(e) ? [t] : [t, ...(D(o, "PATH") || "").split(";")];
287
+ function de(e, o, t) {
288
+ let n = (P(o, "PATHEXT") || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean), s = n.some((l) => e.toLowerCase().endsWith(l.toLowerCase())) ? ["", ...n] : [...n, ""], i = /[\\/]/.test(e) ? [t] : [t, ...(P(o, "PATH") || "").split(";")];
299
289
  for (let l of i)
300
- for (let h of s) {
301
- let u = P.resolve(t, l.replace(/^"|"$/g, ""), e + h);
290
+ for (let d of s) {
291
+ let p = L.resolve(t, l.replace(/^"|"$/g, ""), e + d);
302
292
  try {
303
- if (oe.statSync(u).isFile())
304
- return u;
293
+ if (fe.statSync(p).isFile())
294
+ return p;
305
295
  } catch {}
306
296
  }
307
297
  }
308
- function ie(e, o, t) {
298
+ function pe(e, o, t) {
309
299
  if (process.platform !== "win32")
310
- return $.spawn(e, o, t);
311
- let n = t.env || process.env, r = se(e, n, t.cwd || process.cwd());
300
+ return _.spawn(e, o, t);
301
+ let n = t.env || process.env, r = de(e, n, t.cwd || process.cwd());
312
302
  if (r && /\.(?:exe|com)$/i.test(r))
313
- return $.spawn(r, o, t);
314
- let s = /\.(?:bat|cmd)$/i.test(r || e), i = [_(P.normalize(r || e))];
315
- for (let h of o)
316
- i.push(_(ne(h), s ? 2 : 1));
303
+ return _.spawn(r, o, t);
304
+ let s = /\.(?:bat|cmd)$/i.test(r || e), i = [H(L.normalize(r || e))];
305
+ for (let d of o)
306
+ i.push(H(ue(d), s ? 2 : 1));
317
307
  let l = i.join(" ");
318
- return $.spawn(D(n, "COMSPEC") || "cmd.exe", ["/d", "/v:off", "/s", "/c", `"${l}"`], { ...t, windowsVerbatimArguments: true });
308
+ return _.spawn(P(n, "COMSPEC") || "cmd.exe", ["/d", "/v:off", "/s", "/c", `"${l}"`], { ...t, windowsVerbatimArguments: true });
319
309
  }
320
- R.exports = ie;
310
+ W.exports = pe;
321
311
  });
322
- var V = O((Ae, S) => {
323
- var ce = __require("fs"), ae = __require("os"), G = __require("path"), le = __require("child_process"), fe = F(), k = y(), { optionsFromEnv: ue } = q();
324
- function A() {
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 $() {
325
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(`
326
316
  `));
327
317
  }
328
- function de(e) {
318
+ function we(e) {
329
319
  let o = [], t = false, n, r, s, i, l = -1;
330
- for (let u = 0;u < e.length; u++) {
331
- let f = e[u];
320
+ for (let p = 0;p < e.length; p++) {
321
+ let f = e[p];
332
322
  if (f === "--") {
333
- l = u + 1;
323
+ l = p + 1;
334
324
  break;
335
325
  }
336
326
  if (f === "--help" || f === "-h")
@@ -352,70 +342,70 @@ var require_dist = __commonJS(function(exports, module) {
352
342
  continue;
353
343
  }
354
344
  if (f === "-f" || f === "--file" || f.startsWith("-f=") || f.startsWith("--file=")) {
355
- let c = f.indexOf("="), a = c === -1 ? f : f.slice(0, c), d = c === -1 ? e[++u] : f.slice(c + 1);
356
- if (!d || d === "--")
345
+ let c = f.indexOf("="), a = c === -1 ? f : f.slice(0, c), g = c === -1 ? e[++p] : f.slice(c + 1);
346
+ if (!g || g === "--")
357
347
  return { error: `${a} requires a path` };
358
- let p = d.split(",").map((m) => m.trim()).filter(Boolean);
359
- if (p.length === 0)
348
+ let h = g.split(",").map((y) => y.trim()).filter(Boolean);
349
+ if (h.length === 0)
360
350
  return { error: `${a} requires a path` };
361
- o.push(...p), t = true;
351
+ o.push(...h), t = true;
362
352
  continue;
363
353
  }
364
354
  if (f.startsWith("-"))
365
355
  return { error: `unknown option: ${f}` };
366
- l = u;
356
+ l = p;
367
357
  break;
368
358
  }
369
- let h = l === -1 ? [] : e.slice(l);
370
- return { paths: o, pathSet: t, quiet: n, debug: r, override: s, fast: i, command: h };
359
+ let d = l === -1 ? [] : e.slice(l);
360
+ return { paths: o, pathSet: t, quiet: n, debug: r, override: s, fast: i, command: d };
371
361
  }
372
- function pe(e) {
373
- return e[0] === "~" ? G.join(ae.homedir(), e.slice(1)) : e;
362
+ function Ae(e) {
363
+ return e[0] === "~" ? Q.join(ge.homedir(), e.slice(1)) : e;
374
364
  }
375
- function he(e) {
376
- let o = ue(), t = { encoding: o.encoding || "utf8", quiet: o.quiet === true, debug: o.debug === true, override: o.override === true, fast: o.fast === true, paths: [".env"], defaultPath: true };
365
+ function Ee(e) {
366
+ let o = Ce(), t = { encoding: o.encoding || "utf8", quiet: o.quiet === true, debug: o.debug === true, override: o.override === true, fast: o.fast === true, paths: [".env"], defaultPath: true };
377
367
  return o.path != null && (t.paths = [o.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
378
368
  }
379
- function ge(e) {
369
+ function be(e) {
380
370
  let o = {}, t = [], n = { override: e.override, debug: e.debug };
381
371
  for (let s of e.paths) {
382
- let i = G.resolve(process.cwd(), pe(s));
372
+ let i = Q.resolve(process.cwd(), Ae(s));
383
373
  try {
384
- let l = k.parse(ce.readFileSync(i, { encoding: e.encoding }), { fast: e.fast });
385
- k.populate(o, l, n), t.push(s);
374
+ let l = R.parse(he.readFileSync(i, { encoding: e.encoding }), { fast: e.fast });
375
+ R.populate(o, l, n), t.push(s);
386
376
  } catch (l) {
387
377
  if (e.debug && console.log(`\u2506 failed to load ${s} ${l.message}`), !(e.defaultPath && l.code === "ENOENT"))
388
378
  throw l;
389
379
  }
390
380
  }
391
- return { injected: k.populate(process.env, o, n), loadedPaths: t };
381
+ return { injected: R.populate(process.env, o, n), loadedPaths: t };
392
382
  }
393
- function U(e) {
383
+ function J(e) {
394
384
  let o = e[0];
395
385
  if (o === "--help" || o === "-h") {
396
- A();
386
+ $();
397
387
  return;
398
388
  }
399
389
  if (o !== "run") {
400
- A(), process.exitCode = 1;
390
+ $(), process.exitCode = 1;
401
391
  return;
402
392
  }
403
- let t = de(e.slice(1));
393
+ let t = we(e.slice(1));
404
394
  if (t.help) {
405
- A();
395
+ $();
406
396
  return;
407
397
  }
408
398
  if (t.error) {
409
- console.error(`dotenv: ${t.error}`), A(), process.exitCode = 1;
399
+ console.error(`dotenv: ${t.error}`), $(), process.exitCode = 1;
410
400
  return;
411
401
  }
412
402
  if (t.command.length === 0) {
413
- A(), process.exitCode = 1;
403
+ $(), process.exitCode = 1;
414
404
  return;
415
405
  }
416
- let n = he(t);
406
+ let n = Ee(t);
417
407
  try {
418
- let c = ge(n);
408
+ let c = be(n);
419
409
  if (!n.quiet) {
420
410
  let a = `\u25C7 injected env (${Object.keys(c.injected).length})`;
421
411
  c.loadedPaths.length > 0 && (a += ` from ${c.loadedPaths.join(", ")}`), console.error(a);
@@ -424,11 +414,11 @@ var require_dist = __commonJS(function(exports, module) {
424
414
  console.error(`dotenv: ${c.message}`), process.exitCode = 1;
425
415
  return;
426
416
  }
427
- let r = !!process.stdin.isTTY, s = process.platform !== "win32" && !r, i = fe(t.command[0], t.command.slice(1), { stdio: "inherit", detached: s }), l = new Map, h = 0;
428
- function u(c) {
417
+ let r = !!process.stdin.isTTY, s = process.platform !== "win32" && !r, i = ve(t.command[0], t.command.slice(1), { stdio: "inherit", detached: s }), l = new Map, d = 0;
418
+ function p(c) {
429
419
  if (!(!i.pid || i.exitCode !== null || i.signalCode !== null)) {
430
420
  if (process.platform === "win32") {
431
- le.spawnSync("taskkill", ["/pid", String(i.pid), "/T", "/F"], { stdio: "ignore" });
421
+ me.spawnSync("taskkill", ["/pid", String(i.pid), "/T", "/F"], { stdio: "ignore" });
432
422
  return;
433
423
  }
434
424
  try {
@@ -446,14 +436,14 @@ var require_dist = __commonJS(function(exports, module) {
446
436
  for (let c of ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"]) {
447
437
  let a = () => {
448
438
  if (c === "SIGINT") {
449
- if (h++, r && process.platform !== "win32" && h === 1)
439
+ if (d++, r && process.platform !== "win32" && d === 1)
450
440
  return;
451
- if (h > 1) {
452
- u(h === 2 ? "SIGTERM" : "SIGKILL");
441
+ if (d > 1) {
442
+ p(d === 2 ? "SIGTERM" : "SIGKILL");
453
443
  return;
454
444
  }
455
445
  }
456
- u(c);
446
+ p(c);
457
447
  };
458
448
  l.set(c, a), process.on(c, a);
459
449
  }
@@ -463,16 +453,16 @@ var require_dist = __commonJS(function(exports, module) {
463
453
  f(), typeof c == "number" ? process.exit(c) : (setInterval(() => {}, 1000), process.kill(process.pid, a));
464
454
  });
465
455
  }
466
- S.exports = U;
467
- S === __require.main && U(process.argv.slice(2));
456
+ F.exports = J;
457
+ F === __require.main && J(process.argv.slice(2));
468
458
  });
469
- var E = y();
470
- var ve = V();
471
- module.exports = E;
472
- module.exports.config = E.config;
473
- module.exports.configDotenv = E.configDotenv;
474
- module.exports.parse = E.parse;
475
- module.exports.populate = E.populate;
459
+ var D = N();
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;
476
466
  });
477
467
 
478
468
  // src/load-env.ts
@@ -8504,7 +8494,8 @@ var assertSensitiveWorkflowConfirmed = async (input) => {
8504
8494
  await confirmCurrentCommand({
8505
8495
  action: input.action,
8506
8496
  target: input.entity,
8507
- details: input.details
8497
+ details: input.details,
8498
+ effects: input.effects
8508
8499
  });
8509
8500
  return;
8510
8501
  }
@@ -9953,6 +9944,17 @@ async function getSupplierDetails(supplierId) {
9953
9944
  });
9954
9945
  }
9955
9946
  async function approveSupplier(supplierId) {
9947
+ const supplier = await api2.supplier.getSupplierById.query({ id: supplierId });
9948
+ if (supplier.status === ExtendedApprovalStatus.REJECTED) {
9949
+ await assertSensitiveWorkflowConfirmed({
9950
+ action: "Re-approve supplier",
9951
+ entity: `supplier ${supplierId}`,
9952
+ effects: ["state-change", "external-write"],
9953
+ details: supplier.active ? "and sync its details with QuickBooks; append a new approval and retain earlier history; no requester reply email is sent" : "and sync its details with QuickBooks; append a new approval and retain earlier history; it remains archived and no requester reply email is sent"
9954
+ });
9955
+ out(await api2.supplier.reapproveSupplier.mutate({ supplierId }));
9956
+ return;
9957
+ }
9956
9958
  await assertSensitiveWorkflowConfirmed({
9957
9959
  action: "Approve supplier",
9958
9960
  entity: `supplier ${supplierId}`,
@@ -10894,6 +10896,8 @@ var effectsFor = (legacyTarget) => {
10894
10896
  };
10895
10897
  var titleCase = (value) => value.split("-").map((word) => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`).join(" ");
10896
10898
  var summaryFor = (legacyTarget) => {
10899
+ if (legacyTarget === "approve-supplier")
10900
+ return "Approve a pending supplier request and send a requester reply email, or directly re-approve a rejected supplier as Admin/Lead without a pending request or email. QuickBooks is synchronized; archived suppliers remain archived. Argument: <supplierId>.";
10897
10901
  if (legacyTarget === "search-existing-companies")
10898
10902
  return "Search BB and QuickBooks companies without writes. --query <name> [--page <number>].";
10899
10903
  if (legacyTarget === "use-existing-company")
@@ -11823,7 +11827,7 @@ Approvals
11823
11827
  reject-bill <billId> --reason <text> (also sends requester reply email)
11824
11828
  approve-budget <budgetId> (also sends requester reply email)
11825
11829
  reject-budget <budgetId> --reason <text> (also sends requester reply email)
11826
- approve-supplier <supplierId> (also sends requester reply email)
11830
+ approve-supplier <supplierId> (approve a pending request, or Admin/Lead re-approve a rejected supplier)
11827
11831
  reject-supplier <supplierId> --reason <text> (also sends requester reply email)
11828
11832
 
11829
11833
  Companies & projects
@@ -12258,7 +12262,7 @@ Waiting for approval\u2026
12258
12262
  }
12259
12263
  configureAccessToken(accessToken);
12260
12264
  }
12261
- if (!resolvedCommand.isLegacyAlias && cmd !== "create-bill" && cmd !== "import-qbo-customer-invoice" && resolvedCommand.command.effects.length > 0) {
12265
+ if (!resolvedCommand.isLegacyAlias && cmd !== "create-bill" && cmd !== "import-qbo-customer-invoice" && cmd !== "approve-supplier" && resolvedCommand.command.effects.length > 0) {
12262
12266
  await confirmCurrentCommand({
12263
12267
  action: resolvedCommand.command.path.join(" "),
12264
12268
  target: commandConfirmationTarget(resolvedCommand),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/bb",
3
- "version": "2.44.0",
3
+ "version": "2.45.1",
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",
@@ -25,7 +25,7 @@ The Budget Builder API, not the CLI, makes the final decision. A request may nee
25
25
  2. A sufficient current database role: `USER`, `INSIDE_SALES`, `LEAD`, `ACCOUNTING_TEAM`, or `ADMIN`. Pending approval assignment does not preserve decision authority after a role change.
26
26
  3. Access to the specific resource, commonly through creator ownership or project assignment as Business Development, Inside Sales, or Project Manager.
27
27
  4. A compatible resource state, such as a bill being `DRAFT` or `REJECTED` before editing.
28
- 5. A pending approval record assigned to the current user for approval decisions.
28
+ 5. A pending approval record assigned to the current user for request decisions. Direct Admin/Lead re-approval of a rejected supplier does not require a pending request.
29
29
  6. Required evidence and consistent related records, such as payment proof, approved quotation coverage, or matching project/budget IDs.
30
30
 
31
31
  Therefore, two users with the same role can receive different results for the same command and different resource IDs.
@@ -95,7 +95,8 @@ This table highlights the role-sensitive command groups an agent is most likely
95
95
  | `bb project hub status`, `bb project hub setup`, and `bb project hub sync` | `ADMIN`, project creator, or project assignment as Business Development, Inside Sales, or Project Manager. Setup and sync also enforce Project Hub lifecycle/readiness checks. |
96
96
  | `bb supplier update`, `bb item update`, `bb item category update` | Any active authenticated role. Normal-user supplier edits are submitted for approval by the shared API; item/category edits apply immediately. Human review and provider synchronization can temporarily block further supplier edits/new usage. |
97
97
  | Edit/delete a bill or quotation | Usually creator or `ADMIN`, with a supported status. |
98
- | `bb budget approve`, `bb budget reject`, `bb supplier approve`, and `bb supplier reject` | Current user must be the pending approver and currently have role `LEAD` or `ADMIN`. |
98
+ | `bb budget approve`, `bb budget reject`, and `bb supplier reject` | Current user must be the pending approver and currently have role `LEAD` or `ADMIN`. |
99
+ | `bb supplier approve` | `LEAD` or `ADMIN`. Pending suppliers require an assigned pending request; rejected suppliers can be directly re-approved without one. Re-approval preserves archive state and does not send a requester email. |
99
100
  | `bb bill approve` and `bb bill reject` | Current user must be the pending approver and currently have role `ACCOUNTING_TEAM` for the finance/check stage or `ADMIN` for the final approval stage. |
100
101
  | `bb quotation approve` and `bb quotation reject` | Current user must be the pending approver and currently have role `ADMIN`; a normal submitter cannot decide the quotation. |
101
102
  | `bb bill status update ... CHECKED` | `ACCOUNTING_TEAM` or `ADMIN`. |