braaand 0.1.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 +37 -0
- package/dist/api.d.ts +9 -0
- package/dist/api.js +61 -0
- package/dist/api.js.map +1 -0
- package/dist/commands/assets.d.ts +7 -0
- package/dist/commands/assets.js +80 -0
- package/dist/commands/assets.js.map +1 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.js +66 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/brands.d.ts +7 -0
- package/dist/commands/brands.js +86 -0
- package/dist/commands/brands.js.map +1 -0
- package/dist/commands/onboard.d.ts +1 -0
- package/dist/commands/onboard.js +35 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/render.d.ts +5 -0
- package/dist/commands/render.js +45 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +188 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/templates.d.ts +5 -0
- package/dist/commands/templates.js +41 -0
- package/dist/commands/templates.js.map +1 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +50 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +158 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# braaand
|
|
2
|
+
|
|
3
|
+
CLI for [Braaand](https://braaand.ai) — brand infrastructure for agentic automation.
|
|
4
|
+
|
|
5
|
+
Manage brands, assets, templates, and renders from the terminal. AI agents use the same tool via Claude Code skills.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g braaand
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Auth
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
braaand auth login # Device auth flow
|
|
17
|
+
braaand auth status # Check connection
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
braaand brands list # List brands
|
|
24
|
+
braaand brands config <brandId> # Get brand config
|
|
25
|
+
braaand brands info <brandId> # Full dump with asset URLs
|
|
26
|
+
braaand assets list <brandId> # List assets
|
|
27
|
+
braaand assets upload <brandId> <file> # Upload asset
|
|
28
|
+
braaand templates discover <brandId> # Agent-facing catalog
|
|
29
|
+
braaand system-templates list # Browse system templates
|
|
30
|
+
braaand render <brandId> <templateId> # Render to PNG
|
|
31
|
+
braaand onboard <file.json> # Create brand + config + assets
|
|
32
|
+
braaand sync # Sync brand assets locally
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## More
|
|
36
|
+
|
|
37
|
+
See [braaand.ai](https://braaand.ai) for full documentation.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
constructor(status: number, message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function apiFetch(path: string, options?: RequestInit): Promise<unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Unauthenticated fetch for public endpoints (device auth).
|
|
8
|
+
*/
|
|
9
|
+
export declare function publicFetch(url: string, options?: RequestInit): Promise<unknown>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getApiKey, getConfig } from "./config.js";
|
|
2
|
+
export class ApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
constructor(status, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export async function apiFetch(path, options = {}) {
|
|
10
|
+
const config = getConfig();
|
|
11
|
+
const apiKey = getApiKey();
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new ApiError(401, "Not authenticated. Run: braaand auth login");
|
|
14
|
+
}
|
|
15
|
+
const url = `${config.apiUrl}${path}`;
|
|
16
|
+
const res = await fetch(url, {
|
|
17
|
+
...options,
|
|
18
|
+
headers: {
|
|
19
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
...options.headers,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
const body = await res.text();
|
|
26
|
+
let message;
|
|
27
|
+
try {
|
|
28
|
+
const json = JSON.parse(body);
|
|
29
|
+
message = json.error || json.message || body;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
message = body;
|
|
33
|
+
}
|
|
34
|
+
throw new ApiError(res.status, `${res.status} ${message}`);
|
|
35
|
+
}
|
|
36
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
37
|
+
if (contentType.includes("application/json")) {
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
return res.text();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Unauthenticated fetch for public endpoints (device auth).
|
|
44
|
+
*/
|
|
45
|
+
export async function publicFetch(url, options = {}) {
|
|
46
|
+
const res = await fetch(url, {
|
|
47
|
+
...options,
|
|
48
|
+
headers: {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
...options.headers,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const body = await res.text();
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(body);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return body;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,OAAO,QAAS,SAAQ,KAAK;IACd;IAAnB,YAAmB,MAAc,EAAE,OAAe;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QADE,WAAM,GAAN,MAAM,CAAQ;IAEjC,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,UAAuB,EAAE;IAEzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,4CAA4C,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,GAAG,OAAO;QACV,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,MAAM,EAAE;YACnC,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO,CAAC,OAAO;SACnB;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9B,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC1D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,UAAuB,EAAE;IAEzB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,GAAG,OAAO;QACV,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO,CAAC,OAAO;SACnB;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { basename, extname } from "path";
|
|
3
|
+
import { getApiKey, getConfig } from "../config.js";
|
|
4
|
+
import { apiFetch } from "../api.js";
|
|
5
|
+
const MIME_MAP = {
|
|
6
|
+
".svg": "image/svg+xml",
|
|
7
|
+
".png": "image/png",
|
|
8
|
+
".jpg": "image/jpeg",
|
|
9
|
+
".jpeg": "image/jpeg",
|
|
10
|
+
".webp": "image/webp",
|
|
11
|
+
".gif": "image/gif",
|
|
12
|
+
".woff": "font/woff",
|
|
13
|
+
".woff2": "font/woff2",
|
|
14
|
+
".ttf": "font/ttf",
|
|
15
|
+
".otf": "font/otf",
|
|
16
|
+
".pdf": "application/pdf",
|
|
17
|
+
};
|
|
18
|
+
function getMime(filename) {
|
|
19
|
+
const ext = extname(filename).toLowerCase();
|
|
20
|
+
return MIME_MAP[ext] || "application/octet-stream";
|
|
21
|
+
}
|
|
22
|
+
export async function list(brandId) {
|
|
23
|
+
if (!brandId) {
|
|
24
|
+
console.error("Usage: braaand assets list <brandId>");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const apiUrl = getConfig().apiUrl;
|
|
28
|
+
const assets = (await apiFetch(`/api/brands/${brandId}/assets`));
|
|
29
|
+
const enriched = assets.map((a) => ({
|
|
30
|
+
...a,
|
|
31
|
+
url: `${apiUrl}/api/brands/${brandId}/assets/${a.id}`,
|
|
32
|
+
}));
|
|
33
|
+
console.log(JSON.stringify(enriched, null, 2));
|
|
34
|
+
}
|
|
35
|
+
export async function upload(brandId, filePath, options) {
|
|
36
|
+
if (!brandId || !filePath) {
|
|
37
|
+
console.error("Usage: braaand assets upload <brandId> <file> [--name <name>] [--type logo|image|font|icon|symbol] [--tags <comma-sep>] [--description <desc>]");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
const apiKey = getApiKey();
|
|
42
|
+
if (!apiKey) {
|
|
43
|
+
console.error("Not authenticated. Run: braaand auth login");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const buffer = readFileSync(filePath);
|
|
47
|
+
const filename = basename(filePath);
|
|
48
|
+
const mime = getMime(filename);
|
|
49
|
+
// Infer asset type from file extension if not specified
|
|
50
|
+
const inferredType = options.type || (() => {
|
|
51
|
+
const ext = extname(filename).toLowerCase();
|
|
52
|
+
if ([".woff", ".woff2", ".ttf", ".otf"].includes(ext))
|
|
53
|
+
return "font";
|
|
54
|
+
if (ext === ".svg")
|
|
55
|
+
return "logo";
|
|
56
|
+
return "image";
|
|
57
|
+
})();
|
|
58
|
+
// Build multipart form data
|
|
59
|
+
const form = new FormData();
|
|
60
|
+
form.append("file", new Blob([buffer], { type: mime }), filename);
|
|
61
|
+
form.append("name", options.name || filename.replace(/\.[^.]+$/, ""));
|
|
62
|
+
form.append("type", inferredType);
|
|
63
|
+
if (options.tags)
|
|
64
|
+
form.append("tags", options.tags);
|
|
65
|
+
if (options.description)
|
|
66
|
+
form.append("description", options.description);
|
|
67
|
+
const res = await fetch(`${config.apiUrl}/api/brands/${brandId}/assets`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
70
|
+
body: form,
|
|
71
|
+
});
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
const text = await res.text();
|
|
74
|
+
console.error(`Upload failed: ${res.status} ${text}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const asset = await res.json();
|
|
78
|
+
console.log(JSON.stringify(asset, null, 2));
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/commands/assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { publicFetch, apiFetch } from "../api.js";
|
|
2
|
+
import { saveCredentials, deleteCredentials, getCredentials, getConfig } from "../config.js";
|
|
3
|
+
export async function login() {
|
|
4
|
+
const config = getConfig();
|
|
5
|
+
const codeUrl = `${config.apiUrl}/api/auth/device/code`;
|
|
6
|
+
console.log("Starting device authorization...\n");
|
|
7
|
+
const data = (await publicFetch(codeUrl, { method: "POST" }));
|
|
8
|
+
console.log(` Open this URL in your browser:`);
|
|
9
|
+
console.log(` ${data.verification_uri}\n`);
|
|
10
|
+
console.log(` Enter code: ${data.user_code}\n`);
|
|
11
|
+
// Try to open browser automatically
|
|
12
|
+
try {
|
|
13
|
+
const { exec } = await import("child_process");
|
|
14
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
15
|
+
exec(`${cmd} "${data.verification_uri}"`);
|
|
16
|
+
console.log(" (Browser opened automatically)\n");
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Silently fail — user can open manually
|
|
20
|
+
}
|
|
21
|
+
// Poll for token
|
|
22
|
+
console.log("Waiting for authorization...");
|
|
23
|
+
const tokenUrl = `${config.apiUrl}/api/auth/device/token`;
|
|
24
|
+
const deadline = Date.now() + data.expires_in * 1000;
|
|
25
|
+
while (Date.now() < deadline) {
|
|
26
|
+
await new Promise((r) => setTimeout(r, data.interval * 1000));
|
|
27
|
+
const result = (await publicFetch(tokenUrl, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
body: JSON.stringify({ device_code: data.device_code }),
|
|
30
|
+
}));
|
|
31
|
+
if (result.access_token) {
|
|
32
|
+
saveCredentials({ apiKey: result.access_token });
|
|
33
|
+
console.log("\nAuthenticated successfully!");
|
|
34
|
+
console.log(`API key saved to ~/.braaand/credentials.json`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (result.error && result.error !== "authorization_pending") {
|
|
38
|
+
console.error(`\nAuthorization failed: ${result.error}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
process.stdout.write(".");
|
|
42
|
+
}
|
|
43
|
+
console.error("\nAuthorization timed out. Please try again.");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
export async function logout() {
|
|
47
|
+
deleteCredentials();
|
|
48
|
+
console.log("Logged out. Credentials removed.");
|
|
49
|
+
}
|
|
50
|
+
export async function status() {
|
|
51
|
+
const creds = getCredentials();
|
|
52
|
+
if (!creds) {
|
|
53
|
+
console.log("Not authenticated. Run: braaand auth login");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(`Authenticated (key: ${creds.apiKey.slice(0, 11)}...)`);
|
|
57
|
+
// Try to fetch brands as a connectivity test
|
|
58
|
+
try {
|
|
59
|
+
const brands = (await apiFetch("/api/brands"));
|
|
60
|
+
console.log(`Connected — ${brands.length} brand(s) accessible`);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
console.log(`Key stored but API unreachable: ${err}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function list(): Promise<void>;
|
|
2
|
+
export declare function create(name: string, description?: string): Promise<void>;
|
|
3
|
+
export declare function get(brandId: string): Promise<void>;
|
|
4
|
+
export declare function config(brandId: string): Promise<void>;
|
|
5
|
+
export declare function info(brandId: string): Promise<void>;
|
|
6
|
+
export declare function knowledge(brandId: string, sectionId?: string): Promise<void>;
|
|
7
|
+
export declare function portal(brandId: string): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { apiFetch } from "../api.js";
|
|
2
|
+
import { getConfig } from "../config.js";
|
|
3
|
+
export async function list() {
|
|
4
|
+
const brands = await apiFetch("/api/brands");
|
|
5
|
+
console.log(JSON.stringify(brands, null, 2));
|
|
6
|
+
}
|
|
7
|
+
export async function create(name, description) {
|
|
8
|
+
if (!name) {
|
|
9
|
+
console.error("Usage: braaand brands create <name> [--description <desc>]");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const brand = await apiFetch("/api/brands", {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body: JSON.stringify({ name, description }),
|
|
15
|
+
});
|
|
16
|
+
console.log(JSON.stringify(brand, null, 2));
|
|
17
|
+
}
|
|
18
|
+
export async function get(brandId) {
|
|
19
|
+
if (!brandId) {
|
|
20
|
+
console.error("Usage: braaand brands get <brandId>");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const brand = await apiFetch(`/api/brands/${brandId}`);
|
|
24
|
+
console.log(JSON.stringify(brand, null, 2));
|
|
25
|
+
}
|
|
26
|
+
export async function config(brandId) {
|
|
27
|
+
if (!brandId) {
|
|
28
|
+
console.error("Usage: braaand brands config <brandId>");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const brandConfig = await apiFetch(`/api/brands/${brandId}/brand-config`);
|
|
32
|
+
console.log(JSON.stringify(brandConfig, null, 2));
|
|
33
|
+
}
|
|
34
|
+
export async function info(brandId) {
|
|
35
|
+
if (!brandId) {
|
|
36
|
+
console.error("Usage: braaand brands info <brandId>");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const apiUrl = getConfig().apiUrl;
|
|
40
|
+
const [brand, brandConfig, assets] = await Promise.all([
|
|
41
|
+
apiFetch(`/api/brands/${brandId}`),
|
|
42
|
+
apiFetch(`/api/brands/${brandId}/brand-config`),
|
|
43
|
+
apiFetch(`/api/brands/${brandId}/assets`),
|
|
44
|
+
]);
|
|
45
|
+
// Enrich assets with URLs
|
|
46
|
+
const enrichedAssets = assets.map((a) => ({
|
|
47
|
+
...a,
|
|
48
|
+
url: `${apiUrl}/api/brands/${brandId}/assets/${a.id}`,
|
|
49
|
+
}));
|
|
50
|
+
console.log(JSON.stringify({ brand, brandConfig, assets: enrichedAssets }, null, 2));
|
|
51
|
+
}
|
|
52
|
+
export async function knowledge(brandId, sectionId) {
|
|
53
|
+
if (!brandId) {
|
|
54
|
+
console.error("Usage: braaand brands knowledge <brandId> [sectionId]");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
const config = (await apiFetch(`/api/brands/${brandId}/brand-config`));
|
|
58
|
+
const sections = config.brandKnowledge || [];
|
|
59
|
+
if (sectionId) {
|
|
60
|
+
const section = sections.find((s) => s.id === sectionId);
|
|
61
|
+
if (!section) {
|
|
62
|
+
console.error(`Section "${sectionId}" not found. Available: ${sections.map((s) => s.id).join(", ") || "none"}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
console.log(JSON.stringify(section, null, 2));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(JSON.stringify(sections, null, 2));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export async function portal(brandId) {
|
|
72
|
+
if (!brandId) {
|
|
73
|
+
console.error("Usage: braaand brands portal <brandId>");
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
const apiUrl = getConfig().apiUrl;
|
|
77
|
+
const url = `${apiUrl}/portal/${brandId}`;
|
|
78
|
+
console.log(url);
|
|
79
|
+
try {
|
|
80
|
+
const { exec } = await import("child_process");
|
|
81
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
82
|
+
exec(`${cmd} "${url}"`);
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=brands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brands.js","sourceRoot":"","sources":["../../src/commands/brands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function onboard(file?: string): Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { apiFetch } from "../api.js";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
export async function onboard(file) {
|
|
4
|
+
let input;
|
|
5
|
+
if (file) {
|
|
6
|
+
input = readFileSync(file, "utf-8");
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
// Read from stdin
|
|
10
|
+
const chunks = [];
|
|
11
|
+
for await (const chunk of process.stdin) {
|
|
12
|
+
chunks.push(chunk);
|
|
13
|
+
}
|
|
14
|
+
input = Buffer.concat(chunks).toString("utf-8");
|
|
15
|
+
}
|
|
16
|
+
if (!input.trim()) {
|
|
17
|
+
console.error("Usage: braaand onboard <file.json>");
|
|
18
|
+
console.error(" or: cat brand.json | braaand onboard");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
let payload;
|
|
22
|
+
try {
|
|
23
|
+
payload = JSON.parse(input);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error("Invalid JSON input");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const result = await apiFetch("/api/onboard", {
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: JSON.stringify(payload),
|
|
32
|
+
});
|
|
33
|
+
console.log(JSON.stringify(result, null, 2));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=onboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/commands/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAa;IACzC,IAAI,KAAa,CAAC;IAElB,IAAI,IAAI,EAAE,CAAC;QACT,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,kBAAkB;QAClB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE;QAC5C,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { getConfig, getApiKey } from "../config.js";
|
|
2
|
+
import { writeFileSync } from "fs";
|
|
3
|
+
export async function render(brandId, templateId, options) {
|
|
4
|
+
if (!brandId || !templateId) {
|
|
5
|
+
console.error("Usage: braaand render <brandId> <templateId> [--format 1x1] [--output file.png] [--overrides '{...}']");
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const body = { brandId, templateId };
|
|
9
|
+
if (options.format)
|
|
10
|
+
body.format = options.format;
|
|
11
|
+
if (options.overrides) {
|
|
12
|
+
try {
|
|
13
|
+
body.elementOverrides = JSON.parse(options.overrides);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
console.error("Invalid JSON in --overrides");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
const apiKey = getApiKey();
|
|
22
|
+
if (!apiKey) {
|
|
23
|
+
console.error("Not authenticated. Run: braaand auth login");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const res = await fetch(`${config.apiUrl}/api/render`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(body),
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text();
|
|
36
|
+
console.error(`Render failed: ${res.status} ${text}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const renderId = res.headers.get("x-render-id") ?? "render";
|
|
40
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
41
|
+
const filename = options.output ?? `${renderId}.png`;
|
|
42
|
+
writeFileSync(filename, buffer);
|
|
43
|
+
console.log(`Rendered to ${filename} (${buffer.length} bytes)`);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAe,EACf,UAAkB,EAClB,OAAiE;IAEjE,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,uGAAuG,CAAC,CAAC;QACvH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAA4B,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACjD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,aAAa,EAAE;QACrD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,MAAM,EAAE;YACnC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,QAAQ,MAAM,CAAC;IAErD,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sync(brandId?: string, dir?: string): Promise<void>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdirSync, rmSync } from "fs";
|
|
2
|
+
import { join, extname } from "path";
|
|
3
|
+
import { apiFetch } from "../api.js";
|
|
4
|
+
import { getConfig, getApiKey } from "../config.js";
|
|
5
|
+
const TYPE_FOLDERS = {
|
|
6
|
+
font: "fonts",
|
|
7
|
+
logo: "logos",
|
|
8
|
+
symbol: "logos",
|
|
9
|
+
image: "images",
|
|
10
|
+
icon: "icons",
|
|
11
|
+
document: "docs",
|
|
12
|
+
};
|
|
13
|
+
function sanitizeFilename(name, ext) {
|
|
14
|
+
// Convert to filesystem-safe name
|
|
15
|
+
const clean = name
|
|
16
|
+
.replace(/[<>:"/\\|?*]/g, "-")
|
|
17
|
+
.replace(/\s+/g, "-")
|
|
18
|
+
.replace(/-+/g, "-")
|
|
19
|
+
.replace(/(^-|-$)/g, "")
|
|
20
|
+
.toLowerCase();
|
|
21
|
+
// Ensure correct extension
|
|
22
|
+
if (clean.endsWith(ext))
|
|
23
|
+
return clean;
|
|
24
|
+
return `${clean}${ext}`;
|
|
25
|
+
}
|
|
26
|
+
function getExtension(filename, mimeType) {
|
|
27
|
+
const ext = extname(filename).toLowerCase();
|
|
28
|
+
if (ext)
|
|
29
|
+
return ext;
|
|
30
|
+
// Fallback to mime type
|
|
31
|
+
const MIME_EXT = {
|
|
32
|
+
"image/svg+xml": ".svg", "image/png": ".png", "image/jpeg": ".jpg",
|
|
33
|
+
"image/webp": ".webp", "font/ttf": ".ttf", "font/otf": ".otf",
|
|
34
|
+
"font/woff": ".woff", "font/woff2": ".woff2", "application/pdf": ".pdf",
|
|
35
|
+
};
|
|
36
|
+
return MIME_EXT[mimeType] || ".bin";
|
|
37
|
+
}
|
|
38
|
+
async function downloadAsset(brandId, assetId, destPath) {
|
|
39
|
+
const config = getConfig();
|
|
40
|
+
const apiKey = getApiKey();
|
|
41
|
+
const url = `${config.apiUrl}/api/brands/${brandId}/assets/${assetId}`;
|
|
42
|
+
const res = await fetch(url, {
|
|
43
|
+
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
44
|
+
});
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
throw new Error(`Failed to download asset ${assetId}: ${res.status}`);
|
|
47
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
48
|
+
writeFileSync(destPath, buffer);
|
|
49
|
+
}
|
|
50
|
+
function loadSyncMetadata(brandDir) {
|
|
51
|
+
const metaPath = join(brandDir, ".braaand.json");
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function saveSyncMetadata(brandDir, meta) {
|
|
60
|
+
writeFileSync(join(brandDir, ".braaand.json"), JSON.stringify(meta, null, 2));
|
|
61
|
+
}
|
|
62
|
+
async function syncBrand(brandId, baseDir) {
|
|
63
|
+
// Fetch brand config and assets in parallel
|
|
64
|
+
const [config, assets] = await Promise.all([
|
|
65
|
+
apiFetch(`/api/brands/${brandId}/brand-config`),
|
|
66
|
+
apiFetch(`/api/brands/${brandId}/assets`),
|
|
67
|
+
]);
|
|
68
|
+
// Use syncName from config as folder name, fall back to brandId
|
|
69
|
+
const folderName = config.syncName || brandId;
|
|
70
|
+
const brandDir = join(baseDir, folderName);
|
|
71
|
+
// Load previous sync state
|
|
72
|
+
const prevMeta = loadSyncMetadata(brandDir);
|
|
73
|
+
const prevAssets = prevMeta?.assets || {};
|
|
74
|
+
// Ensure directory structure
|
|
75
|
+
mkdirSync(brandDir, { recursive: true });
|
|
76
|
+
const usedFolders = new Set();
|
|
77
|
+
// Write brand.json
|
|
78
|
+
writeFileSync(join(brandDir, "brand.json"), JSON.stringify(config, null, 2));
|
|
79
|
+
console.log(` brand.json`);
|
|
80
|
+
// Track current assets
|
|
81
|
+
const currentAssets = {};
|
|
82
|
+
let downloaded = 0;
|
|
83
|
+
let skipped = 0;
|
|
84
|
+
let removed = 0;
|
|
85
|
+
// Download assets
|
|
86
|
+
for (const asset of assets) {
|
|
87
|
+
// Determine folder — check mime type for PDFs that may be typed as "image"
|
|
88
|
+
const isPdf = asset.mimeType === "application/pdf" || asset.filename.endsWith(".pdf");
|
|
89
|
+
const folder = isPdf ? "docs" : (TYPE_FOLDERS[asset.type] || "other");
|
|
90
|
+
usedFolders.add(folder);
|
|
91
|
+
const folderPath = join(brandDir, folder);
|
|
92
|
+
mkdirSync(folderPath, { recursive: true });
|
|
93
|
+
const ext = getExtension(asset.filename, asset.mimeType);
|
|
94
|
+
const localName = sanitizeFilename(asset.name, ext);
|
|
95
|
+
const destPath = join(folderPath, localName);
|
|
96
|
+
// Check if we already have this asset
|
|
97
|
+
const prev = prevAssets[asset.id];
|
|
98
|
+
const needsDownload = !prev
|
|
99
|
+
|| prev.filename !== localName
|
|
100
|
+
|| !existsSync(destPath);
|
|
101
|
+
if (needsDownload) {
|
|
102
|
+
// If renamed, remove old file
|
|
103
|
+
if (prev && prev.filename !== localName) {
|
|
104
|
+
const oldFolder = TYPE_FOLDERS[prev.type] || "other";
|
|
105
|
+
const oldPath = join(brandDir, oldFolder, prev.filename);
|
|
106
|
+
try {
|
|
107
|
+
unlinkSync(oldPath);
|
|
108
|
+
}
|
|
109
|
+
catch { /* already gone */ }
|
|
110
|
+
}
|
|
111
|
+
await downloadAsset(brandId, asset.id, destPath);
|
|
112
|
+
console.log(` ${folder}/${localName}`);
|
|
113
|
+
downloaded++;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
skipped++;
|
|
117
|
+
}
|
|
118
|
+
currentAssets[asset.id] = {
|
|
119
|
+
name: asset.name,
|
|
120
|
+
type: asset.type,
|
|
121
|
+
filename: localName,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Remove assets that no longer exist
|
|
125
|
+
const currentIds = new Set(Object.keys(currentAssets));
|
|
126
|
+
for (const [id, prev] of Object.entries(prevAssets)) {
|
|
127
|
+
if (!currentIds.has(id)) {
|
|
128
|
+
const folder = TYPE_FOLDERS[prev.type] || "other";
|
|
129
|
+
const filePath = join(brandDir, folder, prev.filename);
|
|
130
|
+
try {
|
|
131
|
+
unlinkSync(filePath);
|
|
132
|
+
console.log(` removed ${folder}/${prev.filename}`);
|
|
133
|
+
removed++;
|
|
134
|
+
}
|
|
135
|
+
catch { /* already gone */ }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Clean up empty type folders
|
|
139
|
+
for (const folder of Object.values(TYPE_FOLDERS)) {
|
|
140
|
+
const folderPath = join(brandDir, folder);
|
|
141
|
+
if (existsSync(folderPath)) {
|
|
142
|
+
try {
|
|
143
|
+
const contents = readdirSync(folderPath);
|
|
144
|
+
if (contents.length === 0) {
|
|
145
|
+
rmSync(folderPath, { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch { /* ignore */ }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Save sync metadata
|
|
152
|
+
saveSyncMetadata(brandDir, {
|
|
153
|
+
brandId,
|
|
154
|
+
lastSync: new Date().toISOString(),
|
|
155
|
+
assets: currentAssets,
|
|
156
|
+
});
|
|
157
|
+
const parts = [];
|
|
158
|
+
if (downloaded > 0)
|
|
159
|
+
parts.push(`${downloaded} downloaded`);
|
|
160
|
+
if (skipped > 0)
|
|
161
|
+
parts.push(`${skipped} unchanged`);
|
|
162
|
+
if (removed > 0)
|
|
163
|
+
parts.push(`${removed} removed`);
|
|
164
|
+
console.log(` Done — ${parts.join(", ") || "up to date"}`);
|
|
165
|
+
return folderName;
|
|
166
|
+
}
|
|
167
|
+
export async function sync(brandId, dir) {
|
|
168
|
+
const baseDir = dir || process.cwd();
|
|
169
|
+
if (brandId) {
|
|
170
|
+
console.log(`Syncing ${brandId}...`);
|
|
171
|
+
await syncBrand(brandId, baseDir);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Sync all accessible brands
|
|
175
|
+
const brands = (await apiFetch("/api/brands"));
|
|
176
|
+
if (brands.length === 0) {
|
|
177
|
+
console.log("No brands accessible.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
console.log(`Syncing ${brands.length} brand${brands.length > 1 ? "s" : ""}...\n`);
|
|
181
|
+
for (const brand of brands) {
|
|
182
|
+
console.log(`${brand.name}`);
|
|
183
|
+
await syncBrand(brand.id, baseDir);
|
|
184
|
+
console.log("");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function list(brandId: string): Promise<void>;
|
|
2
|
+
export declare function discover(brandId: string): Promise<void>;
|
|
3
|
+
export declare function get(brandId: string, templateId: string): Promise<void>;
|
|
4
|
+
export declare function systemList(): Promise<void>;
|
|
5
|
+
export declare function systemInstantiate(templateId: string, brandId: string, name?: string): Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { apiFetch } from "../api.js";
|
|
2
|
+
export async function list(brandId) {
|
|
3
|
+
if (!brandId) {
|
|
4
|
+
console.error("Usage: braaand templates list <brandId>");
|
|
5
|
+
process.exit(1);
|
|
6
|
+
}
|
|
7
|
+
const templates = await apiFetch(`/api/brands/${brandId}/templates`);
|
|
8
|
+
console.log(JSON.stringify(templates, null, 2));
|
|
9
|
+
}
|
|
10
|
+
export async function discover(brandId) {
|
|
11
|
+
if (!brandId) {
|
|
12
|
+
console.error("Usage: braaand templates discover <brandId>");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const catalog = await apiFetch(`/api/brands/${brandId}/templates/discover`);
|
|
16
|
+
console.log(JSON.stringify(catalog, null, 2));
|
|
17
|
+
}
|
|
18
|
+
export async function get(brandId, templateId) {
|
|
19
|
+
if (!brandId || !templateId) {
|
|
20
|
+
console.error("Usage: braaand templates get <brandId> <templateId>");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const template = await apiFetch(`/api/brands/${brandId}/templates/${templateId}`);
|
|
24
|
+
console.log(JSON.stringify(template, null, 2));
|
|
25
|
+
}
|
|
26
|
+
export async function systemList() {
|
|
27
|
+
const catalog = await apiFetch("/api/system-templates");
|
|
28
|
+
console.log(JSON.stringify(catalog, null, 2));
|
|
29
|
+
}
|
|
30
|
+
export async function systemInstantiate(templateId, brandId, name) {
|
|
31
|
+
if (!templateId || !brandId) {
|
|
32
|
+
console.error("Usage: braaand system-templates instantiate <templateId> --brand <brandId> [--name <name>]");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const result = await apiFetch(`/api/system-templates/${templateId}/instantiate`, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
body: JSON.stringify({ brandId, name }),
|
|
38
|
+
});
|
|
39
|
+
console.log(JSON.stringify(result, null, 2));
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/commands/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAe;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,eAAe,OAAO,YAAY,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,eAAe,OAAO,qBAAqB,CAAC,CAAC;IAC5E,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAe,EAAE,UAAkB;IAC3D,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,eAAe,OAAO,cAAc,UAAU,EAAE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAkB,EAClB,OAAe,EACf,IAAa;IAEb,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,4FAA4F,CAAC,CAAC;QAC5G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,yBAAyB,UAAU,cAAc,EAAE;QAC/E,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;KACxC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Credentials {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
}
|
|
4
|
+
interface Config {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function getCredentials(): Credentials | null;
|
|
8
|
+
export declare function saveCredentials(creds: Credentials): void;
|
|
9
|
+
export declare function deleteCredentials(): void;
|
|
10
|
+
export declare function getConfig(): Config;
|
|
11
|
+
export declare function saveConfig(config: Partial<Config>): void;
|
|
12
|
+
export declare function getApiKey(): string | null;
|
|
13
|
+
export {};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".braaand");
|
|
5
|
+
const CREDS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
7
|
+
function ensureDir() {
|
|
8
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
9
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function getCredentials() {
|
|
13
|
+
try {
|
|
14
|
+
const raw = readFileSync(CREDS_FILE, "utf-8");
|
|
15
|
+
return JSON.parse(raw);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function saveCredentials(creds) {
|
|
22
|
+
ensureDir();
|
|
23
|
+
writeFileSync(CREDS_FILE, JSON.stringify(creds, null, 2), { mode: 0o600 });
|
|
24
|
+
}
|
|
25
|
+
export function deleteCredentials() {
|
|
26
|
+
try {
|
|
27
|
+
unlinkSync(CREDS_FILE);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// already gone
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function getConfig() {
|
|
34
|
+
try {
|
|
35
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
36
|
+
return { apiUrl: "https://braaand.ai", ...JSON.parse(raw) };
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return { apiUrl: "https://braaand.ai" };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function saveConfig(config) {
|
|
43
|
+
ensureDir();
|
|
44
|
+
const existing = getConfig();
|
|
45
|
+
writeFileSync(CONFIG_FILE, JSON.stringify({ ...existing, ...config }, null, 2));
|
|
46
|
+
}
|
|
47
|
+
export function getApiKey() {
|
|
48
|
+
return getCredentials()?.apiKey ?? null;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AACxD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAUpD,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,UAAU,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,SAAS,EAAE,CAAC;IACZ,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;IAC7B,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,cAAc,EAAE,EAAE,MAAM,IAAI,IAAI,CAAC;AAC1C,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { login, logout, status } from "./commands/auth.js";
|
|
3
|
+
import * as assets from "./commands/assets.js";
|
|
4
|
+
import * as brands from "./commands/brands.js";
|
|
5
|
+
import * as templates from "./commands/templates.js";
|
|
6
|
+
import { render } from "./commands/render.js";
|
|
7
|
+
import { onboard } from "./commands/onboard.js";
|
|
8
|
+
import { sync } from "./commands/sync.js";
|
|
9
|
+
import { saveConfig } from "./config.js";
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const command = args[0];
|
|
12
|
+
const subcommand = args[1];
|
|
13
|
+
function getFlag(name) {
|
|
14
|
+
const idx = args.indexOf(`--${name}`);
|
|
15
|
+
return idx >= 0 ? args[idx + 1] : undefined;
|
|
16
|
+
}
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`
|
|
19
|
+
braaand — CLI for Braaand
|
|
20
|
+
|
|
21
|
+
USAGE
|
|
22
|
+
braaand <command> [subcommand] [options]
|
|
23
|
+
|
|
24
|
+
AUTH
|
|
25
|
+
auth login Authenticate via browser (device flow)
|
|
26
|
+
auth logout Remove stored credentials
|
|
27
|
+
auth status Show auth status and test connectivity
|
|
28
|
+
|
|
29
|
+
ASSETS
|
|
30
|
+
assets list <brandId>
|
|
31
|
+
assets upload <brandId> <file> [--name <name>] [--type logo|image|font|icon|symbol] [--tags <comma-sep>]
|
|
32
|
+
|
|
33
|
+
BRANDS
|
|
34
|
+
brands list List your brands
|
|
35
|
+
brands create <name> [--description <desc>]
|
|
36
|
+
brands get <id> Get brand details
|
|
37
|
+
brands config <id> Get brand config (colors, fonts, voice, tokens)
|
|
38
|
+
brands info <id> Full brand dump (config + assets with URLs)
|
|
39
|
+
brands knowledge <id> [sectionId] Query brand knowledge sections
|
|
40
|
+
brands portal <id> Open brand portal in browser
|
|
41
|
+
|
|
42
|
+
TEMPLATES
|
|
43
|
+
templates list <brandId>
|
|
44
|
+
templates get <brandId> <templateId>
|
|
45
|
+
templates discover <brandId> Full agent-facing catalog
|
|
46
|
+
|
|
47
|
+
SYSTEM TEMPLATES
|
|
48
|
+
system-templates list
|
|
49
|
+
system-templates instantiate <templateId> --brand <brandId> [--name <name>]
|
|
50
|
+
|
|
51
|
+
RENDER
|
|
52
|
+
render <brandId> <templateId> [--format 1x1] [--output file.png] [--overrides '{...}']
|
|
53
|
+
|
|
54
|
+
SYNC
|
|
55
|
+
sync [brandId] Sync brand assets to local folders
|
|
56
|
+
sync --dir <path> Sync into a specific directory (default: cwd)
|
|
57
|
+
|
|
58
|
+
ONBOARD
|
|
59
|
+
onboard <file.json> Create brand + config + assets from JSON
|
|
60
|
+
cat brand.json | onboard Pipe JSON from stdin
|
|
61
|
+
|
|
62
|
+
CONFIG
|
|
63
|
+
config set-url <url> Set API URL (default: https://braaand.ai)
|
|
64
|
+
|
|
65
|
+
OUTPUT
|
|
66
|
+
All commands output JSON to stdout. Pipe to jq for formatting:
|
|
67
|
+
braaand brands list | jq '.[].name'
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
async function main() {
|
|
71
|
+
try {
|
|
72
|
+
switch (command) {
|
|
73
|
+
case "auth":
|
|
74
|
+
switch (subcommand) {
|
|
75
|
+
case "login": return await login();
|
|
76
|
+
case "logout": return logout();
|
|
77
|
+
case "status": return await status();
|
|
78
|
+
default: return printHelp();
|
|
79
|
+
}
|
|
80
|
+
case "assets":
|
|
81
|
+
switch (subcommand) {
|
|
82
|
+
case "list": return await assets.list(args[2]);
|
|
83
|
+
case "upload":
|
|
84
|
+
return await assets.upload(args[2], args[3], {
|
|
85
|
+
name: getFlag("name"),
|
|
86
|
+
type: getFlag("type"),
|
|
87
|
+
tags: getFlag("tags"),
|
|
88
|
+
description: getFlag("description"),
|
|
89
|
+
});
|
|
90
|
+
default: return printHelp();
|
|
91
|
+
}
|
|
92
|
+
case "brands":
|
|
93
|
+
switch (subcommand) {
|
|
94
|
+
case "list": return await brands.list();
|
|
95
|
+
case "create": return await brands.create(args[2], getFlag("description"));
|
|
96
|
+
case "get": return await brands.get(args[2]);
|
|
97
|
+
case "config": return await brands.config(args[2]);
|
|
98
|
+
case "info": return await brands.info(args[2]);
|
|
99
|
+
case "knowledge": return await brands.knowledge(args[2], args[3]);
|
|
100
|
+
case "portal": return await brands.portal(args[2]);
|
|
101
|
+
default: return printHelp();
|
|
102
|
+
}
|
|
103
|
+
case "templates":
|
|
104
|
+
switch (subcommand) {
|
|
105
|
+
case "list": return await templates.list(args[2]);
|
|
106
|
+
case "get": return await templates.get(args[2], args[3]);
|
|
107
|
+
case "discover": return await templates.discover(args[2]);
|
|
108
|
+
default: return printHelp();
|
|
109
|
+
}
|
|
110
|
+
case "system-templates":
|
|
111
|
+
switch (subcommand) {
|
|
112
|
+
case "list": return await templates.systemList();
|
|
113
|
+
case "instantiate":
|
|
114
|
+
return await templates.systemInstantiate(args[2], getFlag("brand"), getFlag("name"));
|
|
115
|
+
default: return printHelp();
|
|
116
|
+
}
|
|
117
|
+
case "render":
|
|
118
|
+
return await render(args[1], args[2], {
|
|
119
|
+
format: getFlag("format"),
|
|
120
|
+
output: getFlag("output"),
|
|
121
|
+
overrides: getFlag("overrides"),
|
|
122
|
+
});
|
|
123
|
+
case "sync": {
|
|
124
|
+
const syncBrandId = args[1]?.startsWith("--") ? undefined : args[1];
|
|
125
|
+
return await sync(syncBrandId, getFlag("dir"));
|
|
126
|
+
}
|
|
127
|
+
case "onboard":
|
|
128
|
+
return await onboard(args[1]);
|
|
129
|
+
case "config":
|
|
130
|
+
if (subcommand === "set-url" && args[2]) {
|
|
131
|
+
saveConfig({ apiUrl: args[2] });
|
|
132
|
+
console.log(`API URL set to ${args[2]}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
return printHelp();
|
|
136
|
+
case "help":
|
|
137
|
+
case "--help":
|
|
138
|
+
case "-h":
|
|
139
|
+
case undefined:
|
|
140
|
+
return printHelp();
|
|
141
|
+
default:
|
|
142
|
+
console.error(`Unknown command: ${command}`);
|
|
143
|
+
printHelp();
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
if (err instanceof Error) {
|
|
149
|
+
console.error(`Error: ${err.message}`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.error(err);
|
|
153
|
+
}
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
main();
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "braaand",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Braaand — brand infrastructure for agentic automation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"braaand": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist", "package.json"],
|
|
10
|
+
"engines": { "node": ">=20" },
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.0.0",
|
|
17
|
+
"@types/node": "^20.0.0"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Nitti AI",
|
|
21
|
+
"homepage": "https://braaand.ai",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/nitti-ai/cb-ad-engine.git",
|
|
25
|
+
"directory": "packages/cli"
|
|
26
|
+
},
|
|
27
|
+
"keywords": ["brand", "ai", "cli", "templates", "assets", "braaand"]
|
|
28
|
+
}
|