@go-labs-sg/bb 1.12.0 → 1.13.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 +1 -1
- package/dist/commands.js +12 -1
- package/dist/index.js +1 -1
- package/dist/parse-mutation-payload.js +13 -4
- package/dist/rich-text.js +34 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Global options and flags use `--key=value` or `--key value` (see `bb help`).
|
|
|
56
56
|
|
|
57
57
|
**Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. If the parent project is `PITCH` or `LOST`, the API now marks it `WON` automatically and, when the `asana-tasks` feature flag is enabled, creates the Asana project/section/tasks automatically. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
|
|
58
58
|
|
|
59
|
-
**Mutations with `--payload`:** Commands such as `create-budget`, `create-bill`, `update-supplier`, etc. take a single JSON object (`--payload '<json>'`) matching the corresponding tRPC procedure input. Use ISO strings for date/datetime fields; the CLI coerces them where needed. The API still validates the full shape. For **`update-project`**, the project window is `dateRange.from` and `dateRange.to` (optional end); there are no separate event-date fields on the project payload. **`create-budget` / `update-budget`** do not accept `asanaTaskId`; configure the deal card on the project (`update-project` / project settings).
|
|
59
|
+
**Mutations with `--payload`:** Commands such as `create-budget`, `create-bill`, `update-supplier`, etc. take a single JSON object (`--payload '<json>'`) matching the corresponding tRPC procedure input. Use ISO strings for date/datetime fields; the CLI coerces them where needed. The API still validates the full shape. Plain `description` fields for item create/update are converted to `descriptionRichText`; pass `descriptionRichText` directly when formatted Tiptap JSON is required. For **`update-project`**, the project window is `dateRange.from` and `dateRange.to` (optional end); there are no separate event-date fields on the project payload. **`create-budget` / `update-budget`** do not accept `asanaTaskId`; configure the deal card on the project (`update-project` / project settings).
|
|
60
60
|
|
|
61
61
|
### Command overview
|
|
62
62
|
|
package/dist/commands.js
CHANGED
|
@@ -5,6 +5,7 @@ import { api } from "./api-client.js";
|
|
|
5
5
|
import { BudgetRole, Deals, ExtendedApprovalStatus, ExtendedApprovalType, ExtendedBudgetStatus, TimeFrame, } from "./filter-enums.js";
|
|
6
6
|
import { billStatusesForApi, } from "./parse-cli-enums.js";
|
|
7
7
|
import { parseBudgetDiscountPayload, parseCompanyUpdatePayload, parseContactCreatePayload, parseContactUpdatePayload, parseCreateBillPayload, parseCreateBudgetPayload, parseItemCreatePayload, parseItemUpdatePayload, parseSupplierCreatePayload, parseSupplierUpdatePayload, parseUpdateBillPayload, parseUpdateBudgetCommissionPayload, parseUpdateBudgetPayload, parseUpdateProjectPayload, } from "./parse-mutation-payload.js";
|
|
8
|
+
import { createRichTextFromPlainText } from "./rich-text.js";
|
|
8
9
|
const BUDGET = "BUDGET";
|
|
9
10
|
const BILL = "BILL";
|
|
10
11
|
const SUPPLIER = "SUPPLIER";
|
|
@@ -396,7 +397,17 @@ export async function addBudgetItems(opts) {
|
|
|
396
397
|
out(result);
|
|
397
398
|
}
|
|
398
399
|
export async function updateBudgetItem(input) {
|
|
399
|
-
const result = await api.budgetItem.updateBudgetItem.mutate(
|
|
400
|
+
const result = await api.budgetItem.updateBudgetItem.mutate({
|
|
401
|
+
...input,
|
|
402
|
+
...(input.description !== undefined &&
|
|
403
|
+
input.descriptionRichText === undefined && {
|
|
404
|
+
descriptionRichText: createRichTextFromPlainText(input.description),
|
|
405
|
+
}),
|
|
406
|
+
...(input.note !== undefined &&
|
|
407
|
+
input.noteRichText === undefined && {
|
|
408
|
+
noteRichText: createRichTextFromPlainText(input.note),
|
|
409
|
+
}),
|
|
410
|
+
});
|
|
400
411
|
out(result);
|
|
401
412
|
}
|
|
402
413
|
export async function removeBudgetItem(budgetItemId) {
|
package/dist/index.js
CHANGED
|
@@ -137,7 +137,7 @@ Budgets
|
|
|
137
137
|
create-budget-approval <budgetId> (also sends approval request emails)
|
|
138
138
|
create-estimate <budgetId> (creates QuickBooks estimate; supports preflight updates)
|
|
139
139
|
add-budget-items --budgetId --items '[{"itemId":"…","quantity":1,"markup":30},…]'
|
|
140
|
-
update-budget-item --id <budgetItemId> [--description] [--note] [--quantity] [--markup] [--cost] [--unitPrice] [--isFreeOfCharge true|false] [--gstInclusive true|false]
|
|
140
|
+
update-budget-item --id <budgetItemId> [--description plain-text] [--note plain-text] [--quantity] [--markup] [--cost] [--unitPrice] [--isFreeOfCharge true|false] [--gstInclusive true|false]
|
|
141
141
|
remove-budget-item <budgetItemId>
|
|
142
142
|
reorder-budget-items <budgetId> --itemIds <csv>
|
|
143
143
|
update-budget-item-supplier --budgetItemId --supplierId
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePlainTextRichTextField } from "./rich-text.js";
|
|
1
2
|
function requireObject(raw, label) {
|
|
2
3
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
3
4
|
throw new Error(`${label} must be a JSON object.`);
|
|
@@ -237,12 +238,20 @@ export function parseSupplierUpdatePayload(raw) {
|
|
|
237
238
|
return raw;
|
|
238
239
|
}
|
|
239
240
|
export function parseItemCreatePayload(raw) {
|
|
240
|
-
requireObject(raw, "create-item payload");
|
|
241
|
-
return
|
|
241
|
+
const input = requireObject(raw, "create-item payload");
|
|
242
|
+
return normalizePlainTextRichTextField({
|
|
243
|
+
input,
|
|
244
|
+
textField: "description",
|
|
245
|
+
richTextField: "descriptionRichText",
|
|
246
|
+
});
|
|
242
247
|
}
|
|
243
248
|
export function parseItemUpdatePayload(raw) {
|
|
244
|
-
requireObject(raw, "update-item payload");
|
|
245
|
-
return
|
|
249
|
+
const input = requireObject(raw, "update-item payload");
|
|
250
|
+
return normalizePlainTextRichTextField({
|
|
251
|
+
input,
|
|
252
|
+
textField: "description",
|
|
253
|
+
richTextField: "descriptionRichText",
|
|
254
|
+
});
|
|
246
255
|
}
|
|
247
256
|
export function parseContactCreatePayload(raw) {
|
|
248
257
|
requireObject(raw, "create-contact-person payload");
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const escapeHtml = (text) => text
|
|
2
|
+
.replace(/&/g, "&")
|
|
3
|
+
.replace(/</g, "<")
|
|
4
|
+
.replace(/>/g, ">")
|
|
5
|
+
.replace(/"/g, """)
|
|
6
|
+
.replace(/'/g, "'");
|
|
7
|
+
export const createRichTextFromPlainText = (text) => {
|
|
8
|
+
const lines = text?.split(/\r?\n/) ?? [];
|
|
9
|
+
const paragraphs = lines.length ? lines : [""];
|
|
10
|
+
return {
|
|
11
|
+
json: {
|
|
12
|
+
type: "doc",
|
|
13
|
+
content: paragraphs.map((line) => ({
|
|
14
|
+
type: "paragraph",
|
|
15
|
+
...(line ? { content: [{ type: "text", text: line }] } : {}),
|
|
16
|
+
})),
|
|
17
|
+
},
|
|
18
|
+
html: paragraphs.map((line) => `<p>${escapeHtml(line)}</p>`).join(""),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export const isRichTextJson = (value) => Boolean(value &&
|
|
22
|
+
typeof value === "object" &&
|
|
23
|
+
"json" in value &&
|
|
24
|
+
"html" in value &&
|
|
25
|
+
typeof value.html === "string");
|
|
26
|
+
export const normalizePlainTextRichTextField = ({ input, textField, richTextField, }) => {
|
|
27
|
+
if (isRichTextJson(input[richTextField]) || input[textField] === undefined) {
|
|
28
|
+
return input;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
...input,
|
|
32
|
+
[richTextField]: createRichTextFromPlainText(String(input[textField] ?? "")),
|
|
33
|
+
};
|
|
34
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/bb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Budget Builder CLI for AI agents — manage budgets, bills, and claims; bill records use isClaimable=false for bills and isClaimable=true for claims.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"postpack": "node scripts/restore-package-json.js"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@trpc/client": "^11.
|
|
24
|
+
"@trpc/client": "^11.18.0",
|
|
25
25
|
"dotenv": "^17.4.2",
|
|
26
26
|
"mime-types": "^3.0.2",
|
|
27
27
|
"superjson": "^2.2.6"
|