@go-labs-sg/bb 2.20.0 → 2.23.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 +58 -27
- package/command-manifest.json +771 -0
- package/command-reference.md +25 -0
- package/dist/index.js +21132 -1995
- package/package.json +2 -2
- package/role-aware-agent-guide.md +2 -2
- package/dist/api-client.js +0 -93
- package/dist/cli-trace.js +0 -86
- package/dist/commands.js +0 -2299
- package/dist/filter-enums.js +0 -58
- package/dist/load-env.js +0 -6
- package/dist/parse-args.js +0 -55
- package/dist/parse-cli-enums.js +0 -336
- package/dist/parse-json-flag.js +0 -20
- package/dist/parse-mutation-payload.js +0 -363
- package/dist/prisma-enums.js +0 -81
- package/dist/registry/generate-command-artifacts.js +0 -36
- package/dist/registry/index.js +0 -645
- package/dist/rich-text.js +0 -34
- package/dist/runtime/confirmation.js +0 -76
- package/dist/runtime/error.js +0 -143
- package/dist/runtime/index.js +0 -6
- package/dist/runtime/output.js +0 -36
- package/dist/runtime/process-runtime.js +0 -28
- package/dist/runtime/sanitize.js +0 -50
- package/dist/runtime/session.js +0 -50
- package/dist/runtime/types.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/bb",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.23.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",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"superjson": "^2.2.6"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"
|
|
28
|
+
"bun": ">=1.4.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Role-aware Budget Builder CLI guide for agents
|
|
2
2
|
|
|
3
|
-
This guide explains how an AI agent should choose Budget Builder CLI commands for the identity behind `BB_API_KEY`. It complements [`bb help`](./README.md#command-overview), which lists commands and arguments but intentionally does not decide authorization on the client. Version 2 documents grouped resource commands (for example, `bb budget get <budget-id>`); flat and `snake_case` commands remain compatibility aliases during the v2 transition.
|
|
3
|
+
This guide explains how an AI agent should choose Budget Builder CLI commands for the current browser-authorized identity or automation identity behind `BB_API_KEY`. It complements [`bb help`](./README.md#command-overview), which lists commands and arguments but intentionally does not decide authorization on the client. Version 2 documents grouped resource commands (for example, `bb budget get <budget-id>`); flat and `snake_case` commands remain compatibility aliases during the v2 transition.
|
|
4
4
|
|
|
5
5
|
## Mandatory preflight
|
|
6
6
|
|
|
7
|
-
Run these commands at the beginning of every agent session and after replacing `BB_API_KEY`:
|
|
7
|
+
Run these commands at the beginning of every agent session, after `bb auth login`, and after replacing `BB_API_KEY`:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
bb version
|
package/dist/api-client.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { createTRPCProxyClient, httpBatchLink, loggerLink, } from "@trpc/client";
|
|
2
|
-
import SuperJSON from "superjson";
|
|
3
|
-
import { sanitizeValueForTrace, shouldLogCliActions } from "./cli-trace.js";
|
|
4
|
-
export const DEFAULT_BUDGET_BUILDER_API_BASE_URL = "https://budget-builder.getout.events";
|
|
5
|
-
const normalizeApiBaseUrl = (value) => {
|
|
6
|
-
const url = new URL(value);
|
|
7
|
-
const isLocalHttp = url.protocol === "http:" &&
|
|
8
|
-
(url.hostname === "localhost" || url.hostname === "127.0.0.1");
|
|
9
|
-
if (url.protocol !== "https:" && !isLocalHttp) {
|
|
10
|
-
throw new Error("Budget Builder API URL must use HTTPS, except for localhost development.");
|
|
11
|
-
}
|
|
12
|
-
url.pathname = url.pathname.replace(/\/$/, "");
|
|
13
|
-
return url.toString().replace(/\/$/, "");
|
|
14
|
-
};
|
|
15
|
-
export let BUDGET_BUILDER_API_BASE_URL = DEFAULT_BUDGET_BUILDER_API_BASE_URL;
|
|
16
|
-
function getAuthHeader() {
|
|
17
|
-
const key = process.env.BB_API_KEY;
|
|
18
|
-
if (!key?.trim())
|
|
19
|
-
return undefined;
|
|
20
|
-
return `Bearer ${key.trim()}`;
|
|
21
|
-
}
|
|
22
|
-
const containsRawApiKey = (value, seen = new WeakSet()) => {
|
|
23
|
-
if (typeof value !== "object" || value === null)
|
|
24
|
-
return false;
|
|
25
|
-
if (seen.has(value))
|
|
26
|
-
return false;
|
|
27
|
-
seen.add(value);
|
|
28
|
-
return Object.entries(value).some(([key, nestedValue]) => (key.toLowerCase() === "apikey" && typeof nestedValue === "string") ||
|
|
29
|
-
containsRawApiKey(nestedValue, seen));
|
|
30
|
-
};
|
|
31
|
-
export const createBudgetBuilderClient = (apiBaseUrl = BUDGET_BUILDER_API_BASE_URL) => createTRPCProxyClient({
|
|
32
|
-
links: [
|
|
33
|
-
loggerLink({
|
|
34
|
-
enabled: (opts) => shouldLogCliActions() &&
|
|
35
|
-
!(opts.direction === "down" && containsRawApiKey(opts.result)),
|
|
36
|
-
colorMode: "ansi",
|
|
37
|
-
withContext: false,
|
|
38
|
-
// tRPC defaults use console.log for requests; stderr keeps stdout JSON-safe for pipes.
|
|
39
|
-
console: {
|
|
40
|
-
log: (...args) => console.error(...args.map((arg) => sanitizeValueForTrace(arg))),
|
|
41
|
-
error: (...args) => console.error(...args.map((arg) => sanitizeValueForTrace(arg))),
|
|
42
|
-
},
|
|
43
|
-
}),
|
|
44
|
-
httpBatchLink({
|
|
45
|
-
url: `${apiBaseUrl}/api/trpc`,
|
|
46
|
-
transformer: SuperJSON,
|
|
47
|
-
headers: () => {
|
|
48
|
-
const headers = {
|
|
49
|
-
"x-trpc-source": "bb-cli",
|
|
50
|
-
};
|
|
51
|
-
const auth = getAuthHeader();
|
|
52
|
-
if (auth)
|
|
53
|
-
headers.Authorization = auth;
|
|
54
|
-
return headers;
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
],
|
|
58
|
-
});
|
|
59
|
-
let activeClient = createBudgetBuilderClient();
|
|
60
|
-
export const configureBudgetBuilderApiBaseUrl = (value) => {
|
|
61
|
-
const normalized = normalizeApiBaseUrl(value);
|
|
62
|
-
BUDGET_BUILDER_API_BASE_URL = normalized;
|
|
63
|
-
activeClient = createBudgetBuilderClient(normalized);
|
|
64
|
-
return normalized;
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* Stable facade used by command handlers. Tests can replace the transport without
|
|
68
|
-
* teaching commands about tRPC or process-wide authentication.
|
|
69
|
-
*/
|
|
70
|
-
export const api = new Proxy({}, {
|
|
71
|
-
get: (_target, property, receiver) => Reflect.get(activeClient, property, receiver),
|
|
72
|
-
});
|
|
73
|
-
export const setBudgetBuilderClientForTesting = (client) => {
|
|
74
|
-
const previous = activeClient;
|
|
75
|
-
activeClient = client;
|
|
76
|
-
return () => {
|
|
77
|
-
activeClient = previous;
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
export class MissingApiKeyError extends Error {
|
|
81
|
-
code = "AUTHENTICATION";
|
|
82
|
-
constructor() {
|
|
83
|
-
super("BB_API_KEY is required. Set it in the environment.");
|
|
84
|
-
this.name = "MissingApiKeyError";
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
export function requireApiKey() {
|
|
88
|
-
const key = process.env.BB_API_KEY?.trim();
|
|
89
|
-
if (!key) {
|
|
90
|
-
throw new MissingApiKeyError();
|
|
91
|
-
}
|
|
92
|
-
return key;
|
|
93
|
-
}
|
package/dist/cli-trace.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Action logging for the CLI (default on).
|
|
3
|
-
* - Lifecycle: `logCliAction` in index (command + timing).
|
|
4
|
-
* - Per API call: tRPC `loggerLink` in api-client when `shouldLogCliActions()`.
|
|
5
|
-
* Logs go to stderr so stdout stays JSON for piping. Use `--quiet` / `-q` / BB_CLI_QUIET=1 to silence.
|
|
6
|
-
*/
|
|
7
|
-
let cliQuietSession = false;
|
|
8
|
-
/** Call from main after `consumeCliQuietFlags`. */
|
|
9
|
-
export const setCliQuiet = (quiet) => {
|
|
10
|
-
cliQuietSession = quiet;
|
|
11
|
-
};
|
|
12
|
-
export const isCliQuiet = () => cliQuietSession || process.env.BB_CLI_QUIET === "1";
|
|
13
|
-
export const shouldLogCliActions = () => !isCliQuiet();
|
|
14
|
-
const SENSITIVE_FLAG = new Set([
|
|
15
|
-
"payload",
|
|
16
|
-
"apikey",
|
|
17
|
-
"bb_api_key",
|
|
18
|
-
"token",
|
|
19
|
-
"password",
|
|
20
|
-
"payment-proof",
|
|
21
|
-
"paymentproof",
|
|
22
|
-
"paymentreference",
|
|
23
|
-
"receipt",
|
|
24
|
-
"secret",
|
|
25
|
-
"authorization",
|
|
26
|
-
]);
|
|
27
|
-
const SENSITIVE_TRACE_FIELD = new Set([
|
|
28
|
-
"paymentproof",
|
|
29
|
-
"paymentproofattachments",
|
|
30
|
-
"paymentproofpath",
|
|
31
|
-
"paymentreference",
|
|
32
|
-
"proof",
|
|
33
|
-
"receipt",
|
|
34
|
-
]);
|
|
35
|
-
const isPresignedUrl = (value) => typeof value === "string" &&
|
|
36
|
-
(/[?&]X-Amz-(?:Algorithm|Credential|Signature)=/i.test(value) ||
|
|
37
|
-
/[?&]X-Goog-(?:Algorithm|Credential|Signature)=/i.test(value));
|
|
38
|
-
export const sanitizeValueForTrace = (value, seen = new WeakSet()) => {
|
|
39
|
-
if (typeof value !== "object" || value === null)
|
|
40
|
-
return value;
|
|
41
|
-
if (seen.has(value))
|
|
42
|
-
return "[circular]";
|
|
43
|
-
seen.add(value);
|
|
44
|
-
if (Array.isArray(value)) {
|
|
45
|
-
return value.map((item) => sanitizeValueForTrace(item, seen));
|
|
46
|
-
}
|
|
47
|
-
const prototype = Object.getPrototypeOf(value);
|
|
48
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
49
|
-
return value;
|
|
50
|
-
return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [
|
|
51
|
-
key,
|
|
52
|
-
SENSITIVE_TRACE_FIELD.has(key.toLowerCase()) ||
|
|
53
|
-
isPresignedUrl(nestedValue)
|
|
54
|
-
? "[redacted]"
|
|
55
|
-
: sanitizeValueForTrace(nestedValue, seen),
|
|
56
|
-
]));
|
|
57
|
-
};
|
|
58
|
-
export const sanitizeFlagsForTrace = (flags) => {
|
|
59
|
-
const out = {};
|
|
60
|
-
for (const [k, v] of Object.entries(flags)) {
|
|
61
|
-
const lower = k.toLowerCase();
|
|
62
|
-
if (SENSITIVE_FLAG.has(lower) ||
|
|
63
|
-
lower.includes("secret") ||
|
|
64
|
-
lower.includes("password")) {
|
|
65
|
-
out[k] =
|
|
66
|
-
typeof v === "string" ? `[redacted ${v.length} chars]` : "[redacted]";
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
out[k] = v;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return out;
|
|
73
|
-
};
|
|
74
|
-
export const consumeCliQuietFlags = (flags) => {
|
|
75
|
-
const fromEnv = process.env.BB_CLI_QUIET === "1";
|
|
76
|
-
const fromFlags = flags.quiet === true || flags.q === true;
|
|
77
|
-
delete flags.quiet;
|
|
78
|
-
delete flags.q;
|
|
79
|
-
return fromEnv || fromFlags;
|
|
80
|
-
};
|
|
81
|
-
/** stderr so stdout remains JSON-only for pipes (same intent as “log what the CLI is doing”). */
|
|
82
|
-
export const logCliAction = (record) => {
|
|
83
|
-
if (!shouldLogCliActions())
|
|
84
|
-
return;
|
|
85
|
-
console.error("[bb]", JSON.stringify({ ...record, ts: new Date().toISOString() }));
|
|
86
|
-
};
|