@growthub/cli 0.3.44 → 0.3.45
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/index.js +4 -4
- package/dist/runtime/server/dist/routes/assets.js +21 -48
- package/dist/utils/banner.js +21 -0
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -146,7 +146,7 @@ For the agent-facing extension workflow, see [docs/CLI_TEMPLATE_CONTRIBUTION_EXT
|
|
|
146
146
|
|
|
147
147
|
## Development Notes
|
|
148
148
|
|
|
149
|
-
- `@growthub/cli` version: `0.3.
|
|
149
|
+
- `@growthub/cli` version: `0.3.45`
|
|
150
150
|
- Node.js: `>=20`
|
|
151
151
|
- Source of truth repo: [Growthub Local](https://github.com/Growthub-ai/growthub-local)
|
|
152
152
|
|
package/dist/index.js
CHANGED
|
@@ -6657,9 +6657,9 @@ import pc2 from "picocolors";
|
|
|
6657
6657
|
function printPaperclipCliBanner() {
|
|
6658
6658
|
const lines = [
|
|
6659
6659
|
"",
|
|
6660
|
-
...GROWTHUB_ART
|
|
6661
|
-
pc2.
|
|
6662
|
-
pc2.bold(
|
|
6660
|
+
...GROWTHUB_ART,
|
|
6661
|
+
pc2.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
6662
|
+
pc2.bold(` ${TAGLINE}`),
|
|
6663
6663
|
""
|
|
6664
6664
|
];
|
|
6665
6665
|
console.log(lines.join("\n"));
|
|
@@ -14727,7 +14727,7 @@ applyDataDirOverride(bootstrapOptions, {
|
|
|
14727
14727
|
loadPaperclipEnvFile(bootstrapOptions.config);
|
|
14728
14728
|
var bootstrapConfig = readConfig(resolveConfigPath(bootstrapOptions.config));
|
|
14729
14729
|
var surfaceRuntime = initializeSurfaceRuntimeContract(resolveSurfaceProfile(bootstrapConfig) ?? void 0);
|
|
14730
|
-
program.name("growthub").description("Growthub CLI \u2014 setup, configure, and run your local Growthub instance").version("0.3.
|
|
14730
|
+
program.name("growthub").description("Growthub CLI \u2014 setup, configure, and run your local Growthub instance").version("0.3.45").addHelpText("after", `
|
|
14731
14731
|
Worker Kits (agent execution environments):
|
|
14732
14732
|
|
|
14733
14733
|
Discovery:
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Router } from "express";
|
|
2
2
|
import multer from "multer";
|
|
3
|
-
import createDOMPurify from "dompurify";
|
|
4
|
-
import { JSDOM } from "jsdom";
|
|
5
3
|
import { createAssetImageMetadataSchema } from "@paperclipai/shared";
|
|
6
4
|
import { assetService, logActivity } from "../services/index.js";
|
|
7
5
|
import { isAllowedContentType, MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
|
|
@@ -15,53 +13,32 @@ const ALLOWED_COMPANY_LOGO_CONTENT_TYPES = new Set([
|
|
|
15
13
|
"image/gif",
|
|
16
14
|
SVG_CONTENT_TYPE,
|
|
17
15
|
]);
|
|
16
|
+
const DISALLOWED_SVG_TAGS = /<\/?\s*(script|foreignObject)\b[^>]*>/gi;
|
|
17
|
+
const DISALLOWED_SVG_BLOCKS = /<\s*(script|foreignObject)\b[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi;
|
|
18
|
+
const XML_DECLARATIONS_AND_COMMENTS = /<\?(?:xml|[\s\S]*?)\?>|<!--[\s\S]*?-->|<!DOCTYPE[\s\S]*?>/gi;
|
|
19
|
+
const EVENT_HANDLER_ATTRS = /\s+on[\w:-]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi;
|
|
20
|
+
const STYLE_ATTRS = /\s+style\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi;
|
|
21
|
+
const HREF_ATTRS = /\s+(href|xlink:href)\s*=\s*("([^"]*)"|'([^']*)'|([^\s>]+))/gi;
|
|
22
|
+
const SVG_ROOT_PATTERN = /^<svg\b[\s\S]*<\/svg>$/i;
|
|
18
23
|
function sanitizeSvgBuffer(input) {
|
|
19
24
|
const raw = input.toString("utf8").trim();
|
|
20
25
|
if (!raw)
|
|
21
26
|
return null;
|
|
22
|
-
const baseDom = new JSDOM("");
|
|
23
|
-
const domPurify = createDOMPurify(baseDom.window);
|
|
24
|
-
domPurify.addHook("uponSanitizeAttribute", (_node, data) => {
|
|
25
|
-
const attrName = data.attrName.toLowerCase();
|
|
26
|
-
const attrValue = (data.attrValue ?? "").trim();
|
|
27
|
-
if (attrName.startsWith("on")) {
|
|
28
|
-
data.keepAttr = false;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if ((attrName === "href" || attrName === "xlink:href") && attrValue && !attrValue.startsWith("#")) {
|
|
32
|
-
data.keepAttr = false;
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
let parsedDom = null;
|
|
36
27
|
try {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
FORBID_TAGS: ["script", "foreignObject"],
|
|
40
|
-
FORBID_CONTENTS: ["script", "foreignObject"],
|
|
41
|
-
RETURN_TRUSTED_TYPE: false,
|
|
42
|
-
});
|
|
43
|
-
parsedDom = new JSDOM(sanitized, { contentType: SVG_CONTENT_TYPE });
|
|
44
|
-
const document = parsedDom.window.document;
|
|
45
|
-
const root = document.documentElement;
|
|
46
|
-
if (!root || root.tagName.toLowerCase() !== "svg")
|
|
28
|
+
const normalized = raw.replace(XML_DECLARATIONS_AND_COMMENTS, "").trim();
|
|
29
|
+
if (!SVG_ROOT_PATTERN.test(normalized))
|
|
47
30
|
return null;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if ((attrName === "href" || attrName === "xlink:href") && attrValue && !attrValue.startsWith("#")) {
|
|
60
|
-
el.removeAttribute(attr.name);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const output = root.outerHTML.trim();
|
|
31
|
+
const sanitized = normalized
|
|
32
|
+
.replace(DISALLOWED_SVG_BLOCKS, "")
|
|
33
|
+
.replace(DISALLOWED_SVG_TAGS, "")
|
|
34
|
+
.replace(EVENT_HANDLER_ATTRS, "")
|
|
35
|
+
.replace(STYLE_ATTRS, "")
|
|
36
|
+
.replace(HREF_ATTRS, (_match, attrName, _fullValue, doubleQuoted, singleQuoted, bare) => {
|
|
37
|
+
const attrValue = (doubleQuoted ?? singleQuoted ?? bare ?? "").trim();
|
|
38
|
+
return attrValue.startsWith("#") ? ` ${attrName}="${attrValue}"` : "";
|
|
39
|
+
})
|
|
40
|
+
.trim();
|
|
41
|
+
const output = sanitized.trim();
|
|
65
42
|
if (!output || !/^<svg[\s>]/i.test(output))
|
|
66
43
|
return null;
|
|
67
44
|
return Buffer.from(output, "utf8");
|
|
@@ -69,10 +46,6 @@ function sanitizeSvgBuffer(input) {
|
|
|
69
46
|
catch {
|
|
70
47
|
return null;
|
|
71
48
|
}
|
|
72
|
-
finally {
|
|
73
|
-
parsedDom?.window.close();
|
|
74
|
-
baseDom.window.close();
|
|
75
|
-
}
|
|
76
49
|
}
|
|
77
50
|
export function assetRoutes(db, storage) {
|
|
78
51
|
const router = Router();
|
|
@@ -306,4 +279,4 @@ export function assetRoutes(db, storage) {
|
|
|
306
279
|
});
|
|
307
280
|
return router;
|
|
308
281
|
}
|
|
309
|
-
//# sourceMappingURL=assets.js.map
|
|
282
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
const GROWTHUB_ART = [
|
|
3
|
+
" ██████╗ ██████╗ ██████╗ ██╗ ██╗████████╗██╗ ██╗██╗ ██╗██████╗ ",
|
|
4
|
+
"██╔════╝ ██╔══██╗██╔═══██╗██║ ██║╚══██╔══╝██║ ██║██║ ██║██╔══██╗",
|
|
5
|
+
"██║ ███╗██████╔╝██║ ██║██║ █╗ ██║ ██║ ███████║██║ ██║██████╔╝",
|
|
6
|
+
"██║ ██║██╔══██╗██║ ██║██║███╗██║ ██║ ██╔══██║██║ ██║██╔══██╗",
|
|
7
|
+
"╚██████╔╝██║ ██║╚██████╔╝╚███╔███╔╝ ██║ ██║ ██║╚██████╔╝██████╔╝",
|
|
8
|
+
" ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ",
|
|
9
|
+
];
|
|
10
|
+
const TAGLINE = "Growth infrastructure over a stable agentic substrate";
|
|
11
|
+
export function printPaperclipCliBanner() {
|
|
12
|
+
const lines = [
|
|
13
|
+
"",
|
|
14
|
+
...GROWTHUB_ART,
|
|
15
|
+
pc.dim(" ───────────────────────────────────────────────────────"),
|
|
16
|
+
pc.bold(` ${TAGLINE}`),
|
|
17
|
+
"",
|
|
18
|
+
];
|
|
19
|
+
console.log(lines.join("\n"));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=banner.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growthub/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.45",
|
|
4
4
|
"description": "Growthub CLI — orchestrate AI agent teams to run a business",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,20 +37,17 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@aws-sdk/client-s3": "^3.888.0",
|
|
39
39
|
"@clack/prompts": "^0.10.0",
|
|
40
|
-
"@paperclipai/server": "0.3.1",
|
|
41
40
|
"ajv": "^8.18.0",
|
|
42
41
|
"ajv-formats": "^3.0.1",
|
|
43
42
|
"better-auth": "1.4.18",
|
|
44
43
|
"chokidar": "^4.0.3",
|
|
45
44
|
"commander": "^13.1.0",
|
|
46
45
|
"detect-port": "^2.1.0",
|
|
47
|
-
"dompurify": "^3.3.2",
|
|
48
46
|
"dotenv": "^17.0.1",
|
|
49
|
-
"drizzle-orm": "0.
|
|
47
|
+
"drizzle-orm": "^0.45.2",
|
|
50
48
|
"embedded-postgres": "^18.1.0-beta.16",
|
|
51
49
|
"express": "^5.1.0",
|
|
52
50
|
"hermes-paperclip-adapter": "0.1.1",
|
|
53
|
-
"jsdom": "^28.1.0",
|
|
54
51
|
"multer": "^2.0.2",
|
|
55
52
|
"open": "^11.0.0",
|
|
56
53
|
"picocolors": "^1.1.1",
|
|
@@ -59,6 +56,6 @@
|
|
|
59
56
|
"pino-pretty": "^13.1.3",
|
|
60
57
|
"postgres": "^3.4.5",
|
|
61
58
|
"ws": "^8.19.0",
|
|
62
|
-
"zod": "^3.
|
|
59
|
+
"zod": "^4.3.6"
|
|
63
60
|
}
|
|
64
61
|
}
|