@growthub/cli 0.3.43 → 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 +5 -1
- package/dist/index.js +7 -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
|
@@ -35,6 +35,7 @@ Use this when you want to create or reopen a full Growthub local surface.
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
growthub
|
|
38
|
+
growthub list
|
|
38
39
|
growthub discover
|
|
39
40
|
growthub onboard
|
|
40
41
|
growthub run
|
|
@@ -55,6 +56,9 @@ Use this when you want a working-directory-ready environment for an agent.
|
|
|
55
56
|
### Discovery
|
|
56
57
|
|
|
57
58
|
```bash
|
|
59
|
+
# Interactive discovery hub
|
|
60
|
+
growthub list
|
|
61
|
+
|
|
58
62
|
# Interactive browser — type filter → kit selector → actions
|
|
59
63
|
growthub kit
|
|
60
64
|
|
|
@@ -142,7 +146,7 @@ For the agent-facing extension workflow, see [docs/CLI_TEMPLATE_CONTRIBUTION_EXT
|
|
|
142
146
|
|
|
143
147
|
## Development Notes
|
|
144
148
|
|
|
145
|
-
- `@growthub/cli` version: `0.3.
|
|
149
|
+
- `@growthub/cli` version: `0.3.45`
|
|
146
150
|
- Node.js: `>=20`
|
|
147
151
|
- Source of truth repo: [Growthub Local](https://github.com/Growthub-ai/growthub-local)
|
|
148
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:
|
|
@@ -14762,6 +14762,9 @@ Instance setup:
|
|
|
14762
14762
|
program.action(async () => {
|
|
14763
14763
|
await runDiscoveryHub();
|
|
14764
14764
|
});
|
|
14765
|
+
program.command("list").description("Open the interactive Growthub discovery hub").action(async () => {
|
|
14766
|
+
await runDiscoveryHub();
|
|
14767
|
+
});
|
|
14765
14768
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
14766
14769
|
const options = actionCommand.optsWithGlobals();
|
|
14767
14770
|
const optionNames = new Set(actionCommand.options.map((option) => option.attributeName()));
|
|
@@ -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
|
}
|