@pinepaper.studio/mcp-server 1.6.20 → 1.6.22
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.de.md +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.hi.md +1 -1
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +96 -5
- package/README.pt-BR.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/build-info.json +3 -3
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.js +3 -3
- package/dist/ontology/upstream-vocabulary.js.map +1 -1
- package/dist/ontology/vocabulary.js +1 -1
- package/dist/ontology/vocabulary.js.map +1 -1
- package/dist/tools/choreograph.d.ts.map +1 -1
- package/dist/tools/choreograph.js +10 -0
- package/dist/tools/choreograph.js.map +1 -1
- package/dist/tools/craft-tools.d.ts +55 -0
- package/dist/tools/craft-tools.d.ts.map +1 -0
- package/dist/tools/craft-tools.js +139 -0
- package/dist/tools/craft-tools.js.map +1 -0
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +117 -7
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/effect-class.d.ts.map +1 -1
- package/dist/tools/effect-class.js +6 -0
- package/dist/tools/effect-class.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +2 -2
- package/dist/tools/engine-lists.js +2 -2
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +4 -0
- package/dist/tools/engine-methods.js.map +1 -1
- package/dist/tools/engine-surface.d.ts +1 -1
- package/dist/tools/engine-surface.d.ts.map +1 -1
- package/dist/tools/engine-surface.js +55 -7
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers/brand-intake.d.ts.map +1 -1
- package/dist/tools/handlers/brand-intake.js +42 -1
- package/dist/tools/handlers/brand-intake.js.map +1 -1
- package/dist/tools/handlers/generate.d.ts +28 -28
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +161 -10
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +7 -0
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.d.ts.map +1 -1
- package/dist/tools/shape-params.js +9 -2
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +9 -0
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +10 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +605 -107
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +1745 -582
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +144 -4
- package/dist/types/schemas.js.map +1 -1
- package/dist/utils/asset-paths.d.ts +11 -0
- package/dist/utils/asset-paths.d.ts.map +1 -0
- package/dist/utils/asset-paths.js +67 -0
- package/dist/utils/asset-paths.js.map +1 -0
- package/dist/utils/safe-fetch.d.ts +28 -0
- package/dist/utils/safe-fetch.d.ts.map +1 -0
- package/dist/utils/safe-fetch.js +221 -0
- package/dist/utils/safe-fetch.js.map +1 -0
- package/dist/vendor/design/bauhaus-generator.d.ts.map +1 -1
- package/dist/vendor/design/bauhaus-generator.js +20 -5
- package/dist/vendor/design/bauhaus-generator.js.map +1 -1
- package/dist/vendor/design/design-style.d.ts +2 -2
- package/dist/vendor/design/design-style.d.ts.map +1 -1
- package/dist/vendor/design/design-style.js +7 -2
- package/dist/vendor/design/design-style.js.map +1 -1
- package/dist/vendor/design/subdivision-tool-schema.d.ts +16 -0
- package/dist/vendor/design/subdivision-tool-schema.d.ts.map +1 -0
- package/dist/vendor/design/subdivision-tool-schema.js +104 -0
- package/dist/vendor/design/subdivision-tool-schema.js.map +1 -0
- package/dist/vendor/design/textile-tool-schema.d.ts +14 -0
- package/dist/vendor/design/textile-tool-schema.d.ts.map +1 -0
- package/dist/vendor/design/textile-tool-schema.js +195 -0
- package/dist/vendor/design/textile-tool-schema.js.map +1 -0
- package/dist/vendor/design/ui-kit-runtime.d.ts +49 -0
- package/dist/vendor/design/ui-kit-runtime.d.ts.map +1 -0
- package/dist/vendor/design/ui-kit-runtime.js +761 -0
- package/dist/vendor/design/ui-kit-runtime.js.map +1 -0
- package/dist/vendor/design/ui-kit-tool-schema.d.ts +280 -0
- package/dist/vendor/design/ui-kit-tool-schema.d.ts.map +1 -0
- package/dist/vendor/design/ui-kit-tool-schema.js +209 -0
- package/dist/vendor/design/ui-kit-tool-schema.js.map +1 -0
- package/manifest.json +29 -1
- package/package.json +7 -4
- package/dist/assets/repositories/openclipart.d.ts +0 -41
- package/dist/assets/repositories/openclipart.d.ts.map +0 -1
- package/dist/assets/repositories/openclipart.js +0 -139
- package/dist/assets/repositories/openclipart.js.map +0 -1
- package/dist/assets/repositories/svgrepo.d.ts +0 -61
- package/dist/assets/repositories/svgrepo.d.ts.map +0 -1
- package/dist/assets/repositories/svgrepo.js +0 -276
- package/dist/assets/repositories/svgrepo.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function allowedAssetRoots(): Promise<string[]>;
|
|
2
|
+
/**
|
|
3
|
+
* The real path of `path` when it is inside an allowed folder, else an error
|
|
4
|
+
* naming the folder to add. A missing file inside the folders gets the OS reason.
|
|
5
|
+
*/
|
|
6
|
+
export declare function confineAssetPath(path: string): Promise<{
|
|
7
|
+
path: string;
|
|
8
|
+
} | {
|
|
9
|
+
error: string;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=asset-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-paths.d.ts","sourceRoot":"","sources":["../../src/utils/asset-paths.ts"],"names":[],"mappings":"AAwBA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAM3D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBlG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep a model-supplied local path inside the folders it may read (CWE-22).
|
|
3
|
+
*
|
|
4
|
+
* Image and media imports read a path from the user's disk and hand its bytes
|
|
5
|
+
* to the page, where they can be exported again. Unbounded, that is a way to
|
|
6
|
+
* lift any image- or media-named file off the machine the server runs on. A
|
|
7
|
+
* path is allowed only when its REAL path (symlinks resolved, so a link inside
|
|
8
|
+
* the working directory cannot point out of it) lies inside the server's
|
|
9
|
+
* working directory, its export folder, or a folder named in
|
|
10
|
+
* PINEPAPER_ASSET_DIRS (path.delimiter-separated; each entry is itself
|
|
11
|
+
* resolved).
|
|
12
|
+
*
|
|
13
|
+
* The export folder is allowed because the server's own results point into
|
|
14
|
+
* it: brand_kit from_url saves the logo there and says to import it with
|
|
15
|
+
* pinepaper_import_image. Refusing that would break the tool's own advice.
|
|
16
|
+
*/
|
|
17
|
+
import { realpath } from 'node:fs/promises';
|
|
18
|
+
import { tmpdir } from 'node:os';
|
|
19
|
+
import { basename, delimiter, dirname, join, resolve, sep } from 'node:path';
|
|
20
|
+
async function real(p) {
|
|
21
|
+
try {
|
|
22
|
+
return await realpath(p);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function allowedAssetRoots() {
|
|
29
|
+
// Same default as getExportDir() in handlers.ts (not imported: that module imports this one).
|
|
30
|
+
const exportDir = process.env.PINEPAPER_EXPORT_DIR || join(tmpdir(), 'pinepaper-exports');
|
|
31
|
+
const entries = [process.cwd(), exportDir, ...(process.env.PINEPAPER_ASSET_DIRS ?? '').split(delimiter).filter(Boolean)];
|
|
32
|
+
const roots = await Promise.all(entries.map((e) => real(resolve(e))));
|
|
33
|
+
return [...new Set(roots.filter((r) => r !== null))];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The real path of `path` when it is inside an allowed folder, else an error
|
|
37
|
+
* naming the folder to add. A missing file inside the folders gets the OS reason.
|
|
38
|
+
*/
|
|
39
|
+
export async function confineAssetPath(path) {
|
|
40
|
+
const roots = await allowedAssetRoots();
|
|
41
|
+
const inside = (p) => roots.some((root) => p === root || p.startsWith(root.endsWith(sep) ? root : root + sep));
|
|
42
|
+
const asked = resolve(path);
|
|
43
|
+
let target;
|
|
44
|
+
try {
|
|
45
|
+
target = await realpath(asked);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
// A missing file outside the folders gets the same answer as a present
|
|
49
|
+
// one, so the error is not a way to probe what exists on disk. (The parent
|
|
50
|
+
// is realpath'd for the comparison: on macOS tmpdir is a /var symlink.)
|
|
51
|
+
const parent = await real(dirname(asked));
|
|
52
|
+
if (!inside(parent ? join(parent, basename(asked)) : asked))
|
|
53
|
+
return outside(path, dirname(asked));
|
|
54
|
+
const why = e instanceof Error ? e.message : 'unknown error';
|
|
55
|
+
return { error: `could not read "${path}": ${why}. Paths are resolved from the server's working directory, so pass an absolute path if in doubt.` };
|
|
56
|
+
}
|
|
57
|
+
if (inside(target))
|
|
58
|
+
return { path: target };
|
|
59
|
+
return outside(path, dirname(target));
|
|
60
|
+
}
|
|
61
|
+
function outside(path, folder) {
|
|
62
|
+
return {
|
|
63
|
+
error: `"${path}" is outside the allowed folders (cwd, the export folder, PINEPAPER_ASSET_DIRS). `
|
|
64
|
+
+ `Add its folder (${folder}) to PINEPAPER_ASSET_DIRS to import it.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=asset-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-paths.js","sourceRoot":"","sources":["../../src/utils/asset-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const MAX_REDIRECTS = 5;
|
|
2
|
+
export interface ResolvedAddress {
|
|
3
|
+
address: string;
|
|
4
|
+
family: 4 | 6;
|
|
5
|
+
}
|
|
6
|
+
/** Seams for tests: DNS, and the pinned transport. */
|
|
7
|
+
export declare const safeFetchDeps: {
|
|
8
|
+
lookup: (host: string) => Promise<ResolvedAddress[]>;
|
|
9
|
+
request: (url: URL, addresses: ResolvedAddress[], init: RequestInit) => Promise<Response>;
|
|
10
|
+
};
|
|
11
|
+
export declare function privateNetworkAllowed(): boolean;
|
|
12
|
+
/** 'metadata' | 'private' | null (public). */
|
|
13
|
+
export declare function classifyAddress(address: string): 'metadata' | 'private' | null;
|
|
14
|
+
export declare class UnsafeUrlError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a URL's host and refuse it unless every address is public.
|
|
19
|
+
* Returns the checked addresses, which the connection is then pinned to.
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkUrl(input: string | URL): Promise<ResolvedAddress[]>;
|
|
22
|
+
/**
|
|
23
|
+
* fetch(), with every hop's address checked and the connection pinned to it.
|
|
24
|
+
* Redirects are followed here; `init.redirect` is ignored. The body is read
|
|
25
|
+
* in full before returning, so the per-request connection can be closed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function safeFetch(input: string | URL, init?: RequestInit): Promise<Response>;
|
|
28
|
+
//# sourceMappingURL=safe-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-fetch.d.ts","sourceRoot":"","sources":["../../src/utils/safe-fetch.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,MAAM,WAAW,eAAe;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE;AAEnE,sDAAsD;AACtD,eAAO,MAAM,aAAa,EAAE;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAI3F,CAAC;AAyBF,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AA6BD,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,CAW9E;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAaD;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA8B9E;AAKD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAa9F"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One guarded fetch for every URL a model hands the server (CWE-918).
|
|
3
|
+
*
|
|
4
|
+
* The server fetches remote images, SVGs and media itself, because the
|
|
5
|
+
* studio page's CSP refuses a third-party fetch. That makes this process a
|
|
6
|
+
* proxy for whatever URL arrives in a tool call, and this process can reach
|
|
7
|
+
* things the model's user never meant to expose: the loopback services of the
|
|
8
|
+
* machine it runs on, the LAN, and a cloud host's metadata endpoint, which
|
|
9
|
+
* hands out credentials. So a URL is resolved here and refused when any
|
|
10
|
+
* address it resolves to is private, loopback, link-local or reserved.
|
|
11
|
+
*
|
|
12
|
+
* Three things a plain address check misses, and how each is closed:
|
|
13
|
+
* - REDIRECTS. A public URL can 302 to http://127.0.0.1/. Redirects are
|
|
14
|
+
* followed here, one hop at a time (at most MAX_REDIRECTS), and every
|
|
15
|
+
* Location is checked by the same rules before it is connected to.
|
|
16
|
+
* - DNS REBINDING. A name can resolve to a public address for the check and
|
|
17
|
+
* to 127.0.0.1 for the connection. The connection is pinned: undici's
|
|
18
|
+
* connect.lookup returns exactly the addresses that were checked, so the
|
|
19
|
+
* socket cannot go anywhere else. (Bun's undici shim ignores
|
|
20
|
+
* connect.lookup; the published bin runs under node, where it holds.
|
|
21
|
+
* Under bun this degrades to check-then-connect.)
|
|
22
|
+
* - MAPPED FORMS. ::ffff:127.0.0.1 and 64:ff9b::7f00:1 are loopback in
|
|
23
|
+
* IPv6 clothing. BlockList matches IPv4 rules against mapped addresses;
|
|
24
|
+
* the NAT64 and 6to4 prefixes are unpacked and checked as IPv4.
|
|
25
|
+
*
|
|
26
|
+
* The opt-in: PINEPAPER_ALLOW_PRIVATE_NETWORK=1 allows loopback, private and
|
|
27
|
+
* LAN addresses, for a local dev server. Cloud metadata addresses stay
|
|
28
|
+
* refused with it set: nothing a design tool does needs them.
|
|
29
|
+
*
|
|
30
|
+
* undici and node:dns are loaded lazily. This module is also bundled into a
|
|
31
|
+
* Cloudflare Worker, which has neither in the same form; there, the literal
|
|
32
|
+
* address is still checked and the platform's own fetch does the rest
|
|
33
|
+
* (Workers cannot open connections to private addresses).
|
|
34
|
+
*
|
|
35
|
+
* Keep this file to node builtins and undici, with no relative imports: the
|
|
36
|
+
* pinning test loads it in a plain node process (bun cannot exercise pinning).
|
|
37
|
+
*/
|
|
38
|
+
import { BlockList, isIP } from 'node:net';
|
|
39
|
+
export const MAX_REDIRECTS = 5;
|
|
40
|
+
/** Seams for tests: DNS, and the pinned transport. */
|
|
41
|
+
export const safeFetchDeps = {
|
|
42
|
+
lookup: defaultLookup,
|
|
43
|
+
request: pinnedRequest,
|
|
44
|
+
};
|
|
45
|
+
const PRIVATE = new BlockList();
|
|
46
|
+
for (const [net, bits] of [
|
|
47
|
+
['0.0.0.0', 8], ['10.0.0.0', 8], ['100.64.0.0', 10], ['127.0.0.0', 8],
|
|
48
|
+
['169.254.0.0', 16], ['172.16.0.0', 12], ['192.0.0.0', 24], ['192.0.2.0', 24],
|
|
49
|
+
['192.168.0.0', 16], ['198.18.0.0', 15], ['198.51.100.0', 24], ['203.0.113.0', 24],
|
|
50
|
+
['224.0.0.0', 4], ['240.0.0.0', 4],
|
|
51
|
+
])
|
|
52
|
+
PRIVATE.addSubnet(net, bits, 'ipv4');
|
|
53
|
+
for (const [net, bits] of [
|
|
54
|
+
// 64:ff9b:1::/48 is NAT64 LOCAL-USE (RFC 8215): it translates to addresses
|
|
55
|
+
// inside the operator's own network, so it is private, not unpacked.
|
|
56
|
+
['::', 96], ['64:ff9b:1::', 48], ['100::', 64], ['2001:db8::', 32], ['fc00::', 7],
|
|
57
|
+
['fe80::', 10], ['fec0::', 10], ['ff00::', 8],
|
|
58
|
+
])
|
|
59
|
+
PRIVATE.addSubnet(net, bits, 'ipv6');
|
|
60
|
+
/** Refused even with the opt-in. */
|
|
61
|
+
const METADATA = new BlockList();
|
|
62
|
+
for (const a of ['169.254.169.254', '169.254.170.2', '100.100.100.200'])
|
|
63
|
+
METADATA.addAddress(a, 'ipv4');
|
|
64
|
+
METADATA.addAddress('fd00:ec2::254', 'ipv6');
|
|
65
|
+
function env(name) {
|
|
66
|
+
return typeof process !== 'undefined' ? process.env?.[name] : undefined;
|
|
67
|
+
}
|
|
68
|
+
export function privateNetworkAllowed() {
|
|
69
|
+
return /^(1|true|yes)$/i.test(env('PINEPAPER_ALLOW_PRIVATE_NETWORK') ?? '');
|
|
70
|
+
}
|
|
71
|
+
/** The IPv4 address an IPv6 address carries, for NAT64 (64:ff9b::/96) and 6to4 (2002::/16). */
|
|
72
|
+
function embeddedIPv4(address) {
|
|
73
|
+
const groups = expandIPv6(address);
|
|
74
|
+
if (!groups)
|
|
75
|
+
return null;
|
|
76
|
+
const v4 = (hi, lo) => `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
|
|
77
|
+
if (groups[0] === 0x64 && groups[1] === 0xff9b && groups.slice(2, 6).every((g) => g === 0))
|
|
78
|
+
return v4(groups[6], groups[7]);
|
|
79
|
+
if (groups[0] === 0x2002)
|
|
80
|
+
return v4(groups[1], groups[2]);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
function expandIPv6(address) {
|
|
84
|
+
let a = address.toLowerCase().split('%')[0];
|
|
85
|
+
// A trailing dotted quad (::ffff:1.2.3.4) becomes two groups.
|
|
86
|
+
const dotted = a.match(/^(.*:)(\d+\.\d+\.\d+\.\d+)$/);
|
|
87
|
+
if (dotted) {
|
|
88
|
+
const o = dotted[2].split('.').map(Number);
|
|
89
|
+
a = `${dotted[1]}${((o[0] << 8) | o[1]).toString(16)}:${((o[2] << 8) | o[3]).toString(16)}`;
|
|
90
|
+
}
|
|
91
|
+
const [head, tail] = a.includes('::') ? a.split('::') : [a, null];
|
|
92
|
+
const h = head ? head.split(':') : [];
|
|
93
|
+
const t = tail ? tail.split(':') : [];
|
|
94
|
+
const fill = tail === null ? [] : new Array(8 - h.length - t.length).fill('0');
|
|
95
|
+
const all = [...h, ...fill, ...t];
|
|
96
|
+
if (all.length !== 8)
|
|
97
|
+
return null;
|
|
98
|
+
return all.map((g) => parseInt(g, 16));
|
|
99
|
+
}
|
|
100
|
+
/** 'metadata' | 'private' | null (public). */
|
|
101
|
+
export function classifyAddress(address) {
|
|
102
|
+
const family = isIP(address);
|
|
103
|
+
if (family === 0)
|
|
104
|
+
return 'private'; // not an address at all: never connect to it
|
|
105
|
+
const type = family === 4 ? 'ipv4' : 'ipv6';
|
|
106
|
+
if (METADATA.check(address, type))
|
|
107
|
+
return 'metadata';
|
|
108
|
+
if (PRIVATE.check(address, type))
|
|
109
|
+
return 'private';
|
|
110
|
+
if (family === 6) {
|
|
111
|
+
const v4 = embeddedIPv4(address);
|
|
112
|
+
if (v4)
|
|
113
|
+
return classifyAddress(v4);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
export class UnsafeUrlError extends Error {
|
|
118
|
+
constructor(message) {
|
|
119
|
+
super(message);
|
|
120
|
+
this.name = 'UnsafeUrlError';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function defaultLookup(host) {
|
|
124
|
+
let dns;
|
|
125
|
+
try {
|
|
126
|
+
dns = await import('node:dns/promises');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return []; // no resolver (a Worker): the literal check already ran
|
|
130
|
+
}
|
|
131
|
+
const all = await dns.lookup(host, { all: true, verbatim: true });
|
|
132
|
+
return all.map((r) => ({ address: r.address, family: r.family === 6 ? 6 : 4 }));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Resolve a URL's host and refuse it unless every address is public.
|
|
136
|
+
* Returns the checked addresses, which the connection is then pinned to.
|
|
137
|
+
*/
|
|
138
|
+
export async function checkUrl(input) {
|
|
139
|
+
let url;
|
|
140
|
+
try {
|
|
141
|
+
url = typeof input === 'string' ? new URL(input) : input;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
throw new UnsafeUrlError(`refused "${String(input)}" — not a valid URL.`);
|
|
145
|
+
}
|
|
146
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
147
|
+
throw new UnsafeUrlError(`refused ${url.href} — only http and https URLs are fetched.`);
|
|
148
|
+
}
|
|
149
|
+
const host = url.hostname.replace(/^\[|\]$/g, '');
|
|
150
|
+
const literal = isIP(host);
|
|
151
|
+
let addresses;
|
|
152
|
+
if (literal) {
|
|
153
|
+
addresses = [{ address: host, family: literal === 6 ? 6 : 4 }];
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
addresses = await safeFetchDeps.lookup(host);
|
|
157
|
+
if (!addresses.length && /(^|\.)localhost$/i.test(host))
|
|
158
|
+
addresses = [{ address: '127.0.0.1', family: 4 }];
|
|
159
|
+
}
|
|
160
|
+
const allowPrivate = privateNetworkAllowed();
|
|
161
|
+
for (const { address } of addresses) {
|
|
162
|
+
const kind = classifyAddress(address);
|
|
163
|
+
if (kind === 'metadata') {
|
|
164
|
+
throw new UnsafeUrlError(`refused ${url.href} — it resolves to ${address}, a cloud metadata address. This is refused even with PINEPAPER_ALLOW_PRIVATE_NETWORK=1.`);
|
|
165
|
+
}
|
|
166
|
+
if (kind === 'private' && !allowPrivate) {
|
|
167
|
+
throw new UnsafeUrlError(`refused ${url.href} — it resolves to ${address}, a private address. Set PINEPAPER_ALLOW_PRIVATE_NETWORK=1 to allow local hosts.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return addresses;
|
|
171
|
+
}
|
|
172
|
+
const REDIRECT = new Set([301, 302, 303, 307, 308]);
|
|
173
|
+
const NULL_BODY = new Set([101, 103, 204, 205, 304]);
|
|
174
|
+
/**
|
|
175
|
+
* fetch(), with every hop's address checked and the connection pinned to it.
|
|
176
|
+
* Redirects are followed here; `init.redirect` is ignored. The body is read
|
|
177
|
+
* in full before returning, so the per-request connection can be closed.
|
|
178
|
+
*/
|
|
179
|
+
export async function safeFetch(input, init = {}) {
|
|
180
|
+
let url = typeof input === 'string' ? new URL(input) : input;
|
|
181
|
+
for (let hop = 0;; hop++) {
|
|
182
|
+
const addresses = await checkUrl(url);
|
|
183
|
+
const res = await safeFetchDeps.request(url, addresses, { ...init, redirect: 'manual' });
|
|
184
|
+
if (!REDIRECT.has(res.status))
|
|
185
|
+
return res;
|
|
186
|
+
const location = res.headers.get('location');
|
|
187
|
+
if (!location)
|
|
188
|
+
return res;
|
|
189
|
+
if (hop >= MAX_REDIRECTS) {
|
|
190
|
+
throw new UnsafeUrlError(`refused ${input} — more than ${MAX_REDIRECTS} redirects.`);
|
|
191
|
+
}
|
|
192
|
+
url = new URL(location, url);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function pinnedRequest(url, addresses, init) {
|
|
196
|
+
const undici = await import('undici').catch(() => null);
|
|
197
|
+
// No undici, or no resolver (a Worker): the platform fetch, which cannot
|
|
198
|
+
// reach private addresses.
|
|
199
|
+
if (!undici || !addresses.length)
|
|
200
|
+
return fetch(url, init);
|
|
201
|
+
const agent = new undici.Agent({
|
|
202
|
+
connect: {
|
|
203
|
+
lookup: (_host, opts, cb) => {
|
|
204
|
+
if (opts?.all)
|
|
205
|
+
cb(null, addresses);
|
|
206
|
+
else
|
|
207
|
+
cb(null, addresses[0].address, addresses[0].family);
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
try {
|
|
212
|
+
const res = await undici.fetch(url, { ...init, dispatcher: agent });
|
|
213
|
+
const body = NULL_BODY.has(res.status) ? null : Buffer.from(await res.arrayBuffer());
|
|
214
|
+
return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
// Bun's undici shim has no close().
|
|
218
|
+
await agent.close?.().catch(() => { });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=safe-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-fetch.js","sourceRoot":"","sources":["../../src/utils/safe-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bauhaus-generator.d.ts","sourceRoot":"","sources":["../../../src/vendor/design/bauhaus-generator.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,yBAAyB,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,eAAO,MAAM,eAAe;;;;;;CAM3B,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"bauhaus-generator.d.ts","sourceRoot":"","sources":["../../../src/vendor/design/bauhaus-generator.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,yBAAyB,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,eAAO,MAAM,eAAe;;;;;;CAM3B,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,kBAAkB,CAyIvF"}
|
|
@@ -16,14 +16,29 @@ export function generateBauhausPoster(options) {
|
|
|
16
16
|
const primaryTextColor = isDark ? BAUHAUS_PALETTE.cream : BAUHAUS_PALETTE.dark;
|
|
17
17
|
const elements = [];
|
|
18
18
|
// 1. Primary Red Circle (large architectural structural shape)
|
|
19
|
-
|
|
19
|
+
//
|
|
20
|
+
// Sized from the SHORTER side, because the text block below it is placed by the height (subtitle at
|
|
21
|
+
// 0.68 × h). Sized from the width, a 1920x1080 circle was 864 px tall and reached y = 1058, so the
|
|
22
|
+
// subtitle (734) and body ran across it; 1280x720 the same. With min(w, h) the circle ends at
|
|
23
|
+
// 0.18h + 0.45h = 0.63h on any landscape canvas, clear of the subtitle. On a portrait canvas the shorter
|
|
24
|
+
// side IS the width, so the default 1080x1350 poster is unchanged (bauhaus-landscape-layout.test.ts).
|
|
25
|
+
const circleSize = Math.round(Math.min(width, height) * 0.45);
|
|
26
|
+
// The headline is a fixed 72 px in a fixed 90 px box at 0.06h, so on a short canvas the divider (0.15h) and
|
|
27
|
+
// the circle (0.18h) would sit inside it: at 1280x720 the title box spans 43–133 and the divider was at 108,
|
|
28
|
+
// through the glyphs. The divider goes no higher than the title box's bottom, and the circle keeps its gap
|
|
29
|
+
// below the divider. Where the proportions already clear (1080x1350: divider 203, title bottom 171), both
|
|
30
|
+
// max() pick the proportional value, so the default poster is unchanged.
|
|
31
|
+
const titleY = Math.round(height * 0.06);
|
|
32
|
+
const titleHeight = 90;
|
|
33
|
+
const dividerY = Math.max(Math.round(height * 0.15), titleY + titleHeight);
|
|
34
|
+
const circleY = Math.max(Math.round(height * 0.18), dividerY + 22);
|
|
20
35
|
elements.push({
|
|
21
36
|
id: "bauhaus-red-circle",
|
|
22
37
|
type: "shape",
|
|
23
38
|
shapeType: "circle",
|
|
24
39
|
fillHex: BAUHAUS_PALETTE.red,
|
|
25
40
|
x: Math.round(width * 0.42),
|
|
26
|
-
y:
|
|
41
|
+
y: circleY,
|
|
27
42
|
width: circleSize,
|
|
28
43
|
height: circleSize,
|
|
29
44
|
hasDropShadow: false,
|
|
@@ -49,7 +64,7 @@ export function generateBauhausPoster(options) {
|
|
|
49
64
|
shapeType: "line",
|
|
50
65
|
fillHex: isDark ? BAUHAUS_PALETTE.yellow : BAUHAUS_PALETTE.dark,
|
|
51
66
|
x: Math.round(width * 0.1),
|
|
52
|
-
y:
|
|
67
|
+
y: dividerY,
|
|
53
68
|
width: Math.round(width * 0.8),
|
|
54
69
|
height: 6,
|
|
55
70
|
hasDropShadow: false,
|
|
@@ -65,9 +80,9 @@ export function generateBauhausPoster(options) {
|
|
|
65
80
|
fontFamily: "Futura, 'Bayer Universal', sans-serif",
|
|
66
81
|
fillHex: primaryTextColor,
|
|
67
82
|
x: Math.round(width * 0.1),
|
|
68
|
-
y:
|
|
83
|
+
y: titleY,
|
|
69
84
|
width: Math.round(width * 0.8),
|
|
70
|
-
height:
|
|
85
|
+
height: titleHeight,
|
|
71
86
|
textAlign: "left",
|
|
72
87
|
});
|
|
73
88
|
// 5. Subtitle Text Block
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bauhaus-generator.js","sourceRoot":"","sources":["../../../src/vendor/design/bauhaus-generator.ts"],"names":[],"mappings":"AAuDA,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA6B;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC;IAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC;IAC5E,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;IAE/E,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bauhaus-generator.js","sourceRoot":"","sources":["../../../src/vendor/design/bauhaus-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Every aesthetic style the generators speak. Sliced from the upstream union. */
|
|
2
|
-
export type DesignStyle = "minimal" | "editorial" | "playful" | "cinematic" | "energetic" | "scrapbook" | "swiss_typographic" | "neumorphic_glass" | "risograph_print" | "cyberpunk_neon" | "bauhaus_geometric" | "art_deco_geometric" | "memphis_group" | "brutalist_raw" | "de_stijl_neoplasticism" | "pop_art_expression" | "vaporwave_retro" | "corporate_memphis" | "y2k_frutiger_aero" | "mid_century_upa" | "comic_benday" | "pixel_art_8bit" | "isometric_lowpoly" | "hand_drawn_sketch" | "claymorphism" | "constructivism_suprematism" | "art_nouveau" | "op_art_psychedelic" | "print_monochrome_crisp" | "print_early_learner" | "print_stem_technical" | "embroidery_tapestry" | "woven_textile";
|
|
3
|
-
/** The same
|
|
2
|
+
export type DesignStyle = "minimal" | "editorial" | "playful" | "cinematic" | "energetic" | "scrapbook" | "swiss_typographic" | "neumorphic_glass" | "risograph_print" | "cyberpunk_neon" | "bauhaus_geometric" | "art_deco_geometric" | "memphis_group" | "brutalist_raw" | "de_stijl_neoplasticism" | "pop_art_expression" | "vaporwave_retro" | "corporate_memphis" | "y2k_frutiger_aero" | "mid_century_upa" | "comic_benday" | "pixel_art_8bit" | "isometric_lowpoly" | "hand_drawn_sketch" | "claymorphism" | "constructivism_suprematism" | "art_nouveau" | "op_art_psychedelic" | "print_monochrome_crisp" | "print_early_learner" | "print_stem_technical" | "embroidery_tapestry" | "woven_textile" | "explainer_ink" | "synthwave_outrun" | "sumi_e_ink" | "flat_design" | "blueprint_schematic";
|
|
3
|
+
/** The same 38 styles as DATA, so a runtime list cannot drift from the type. */
|
|
4
4
|
export declare const DESIGN_STYLES: readonly DesignStyle[];
|
|
5
5
|
//# sourceMappingURL=design-style.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-style.d.ts","sourceRoot":"","sources":["../../../src/vendor/design/design-style.ts"],"names":[],"mappings":"AAWA,kFAAkF;AAClF,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,WAAW,GACX,SAAS,GACT,WAAW,GACX,WAAW,GACX,WAAW,GACX,mBAAmB,GACnB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,oBAAoB,GACpB,eAAe,GACf,eAAe,GACf,wBAAwB,GACxB,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,4BAA4B,GAC5B,aAAa,GACb,oBAAoB,GACpB,wBAAwB,GACxB,qBAAqB,GACrB,sBAAsB,GACtB,qBAAqB,GACrB,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"design-style.d.ts","sourceRoot":"","sources":["../../../src/vendor/design/design-style.ts"],"names":[],"mappings":"AAWA,kFAAkF;AAClF,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,WAAW,GACX,SAAS,GACT,WAAW,GACX,WAAW,GACX,WAAW,GACX,mBAAmB,GACnB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,oBAAoB,GACpB,eAAe,GACf,eAAe,GACf,wBAAwB,GACxB,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,4BAA4B,GAC5B,aAAa,GACb,oBAAoB,GACpB,wBAAwB,GACxB,qBAAqB,GACrB,sBAAsB,GACtB,qBAAqB,GACrB,eAAe,GAEf,eAAe,GACf,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,qBAAqB,CAAC;AAG1B,gFAAgF;AAChF,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAuC9C,CAAC"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/* GENERATED — DO NOT EDIT.
|
|
2
2
|
*
|
|
3
3
|
* Source: mcp-cloud/src/services/content-recipes.ts (DesignStyle union only)
|
|
4
|
-
* sha256:
|
|
4
|
+
* sha256: 4987265fc982ad8d7191733208ccf9c5fad8aa6149c457e23742f66223a1a677
|
|
5
5
|
* Generator: scripts/sync-design-systems.mjs
|
|
6
6
|
*
|
|
7
7
|
* Edit the TypeScript upstream and re-run the generator. A hand edit here is
|
|
8
8
|
* the second copy of the same design vocabulary that the generator exists to
|
|
9
9
|
* prevent, and the provenance test will fail on it.
|
|
10
10
|
*/
|
|
11
|
-
/** The same
|
|
11
|
+
/** The same 38 styles as DATA, so a runtime list cannot drift from the type. */
|
|
12
12
|
export const DESIGN_STYLES = Object.freeze([
|
|
13
13
|
'minimal',
|
|
14
14
|
'editorial',
|
|
@@ -43,5 +43,10 @@ export const DESIGN_STYLES = Object.freeze([
|
|
|
43
43
|
'print_stem_technical',
|
|
44
44
|
'embroidery_tapestry',
|
|
45
45
|
'woven_textile',
|
|
46
|
+
'explainer_ink',
|
|
47
|
+
'synthwave_outrun',
|
|
48
|
+
'sumi_e_ink',
|
|
49
|
+
'flat_design',
|
|
50
|
+
'blueprint_schematic',
|
|
46
51
|
]);
|
|
47
52
|
//# sourceMappingURL=design-style.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-style.js","sourceRoot":"","sources":["../../../src/vendor/design/design-style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"design-style.js","sourceRoot":"","sources":["../../../src/vendor/design/design-style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6CH,gFAAgF;AAChF,MAAM,CAAC,MAAM,aAAa,GAA2B,MAAM,CAAC,MAAM,CAAC;IACjE,SAAS;IACT,WAAW;IACX,SAAS;IACT,WAAW;IACX,WAAW;IACX,WAAW;IACX,mBAAmB;IACnB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,mBAAmB;IACnB,oBAAoB;IACpB,eAAe;IACf,eAAe;IACf,wBAAwB;IACxB,oBAAoB;IACpB,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,iBAAiB;IACjB,cAAc;IACd,gBAAgB;IAChB,mBAAmB;IACnB,mBAAmB;IACnB,cAAc;IACd,4BAA4B;IAC5B,aAAa;IACb,oBAAoB;IACpB,wBAAwB;IACxB,qBAAqB;IACrB,sBAAsB;IACtB,qBAAqB;IACrB,eAAe;IACf,eAAe;IACf,kBAAkB;IAClB,YAAY;IACZ,aAAa;IACb,qBAAqB;CACtB,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subdivision tool schemas for the public MCP server API.
|
|
3
|
+
*
|
|
4
|
+
* Exposes pinepaper_draw_subdivision for autonomous and assisted agents.
|
|
5
|
+
*/
|
|
6
|
+
export interface SubdivisionToolDef {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: "object";
|
|
11
|
+
properties: Record<string, unknown>;
|
|
12
|
+
required?: string[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function subdivisionTools(): SubdivisionToolDef[];
|
|
16
|
+
//# sourceMappingURL=subdivision-tool-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subdivision-tool-schema.d.ts","sourceRoot":"","sources":["../../../src/vendor/design/subdivision-tool-schema.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,wBAAgB,gBAAgB,IAAI,kBAAkB,EAAE,CAyFvD"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* GENERATED — DO NOT EDIT.
|
|
2
|
+
*
|
|
3
|
+
* Source: mcp-cloud/src/services/subdivision-tool-schema.ts
|
|
4
|
+
* sha256: ce1d01ac572d9bbf66ea31160548f657dcf6a294eebb36427be64a458ef92d5c
|
|
5
|
+
* Generator: scripts/sync-design-systems.mjs
|
|
6
|
+
*
|
|
7
|
+
* Edit the TypeScript upstream and re-run the generator. A hand edit here is
|
|
8
|
+
* the second copy of the same design vocabulary that the generator exists to
|
|
9
|
+
* prevent, and the provenance test will fail on it.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Subdivision tool schemas for the public MCP server API.
|
|
13
|
+
*
|
|
14
|
+
* Exposes pinepaper_draw_subdivision for autonomous and assisted agents.
|
|
15
|
+
*/
|
|
16
|
+
export function subdivisionTools() {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
name: "pinepaper_draw_subdivision",
|
|
20
|
+
description: "Generate asymmetric recursive quadtree/rectangular partition compositions (De Stijl/Mondrian, Swiss International Style, Bauhaus, Minimal) with bounded depth, asymmetric rest cell preservation, and crisp orthogonal dividers. Appends to canvas state for rendering and vector export. [Cost: $0.001]",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
preset: {
|
|
25
|
+
type: "string",
|
|
26
|
+
enum: ["mondrian", "swiss", "bauhaus", "minimal", "custom"],
|
|
27
|
+
description: "Style preset: mondrian = primary red/blue/yellow with heavy black dividers; swiss = clean modernist with hairline grid and nested cards; bauhaus = geometric warm parchment palette; minimal = quiet monochromatic; custom = user-specified palette.",
|
|
28
|
+
},
|
|
29
|
+
maxDepth: {
|
|
30
|
+
type: "integer",
|
|
31
|
+
minimum: 1,
|
|
32
|
+
maximum: 6,
|
|
33
|
+
description: "Maximum subdivision recursion depth (default: 4). Bounded to guarantee non-hanging design generation.",
|
|
34
|
+
},
|
|
35
|
+
minDepth: {
|
|
36
|
+
type: "integer",
|
|
37
|
+
minimum: 1,
|
|
38
|
+
maximum: 6,
|
|
39
|
+
description: "Minimum subdivision depth before leaf cells are permitted (default: 2).",
|
|
40
|
+
},
|
|
41
|
+
splitBias: {
|
|
42
|
+
type: "array",
|
|
43
|
+
items: { type: "number" },
|
|
44
|
+
minItems: 2,
|
|
45
|
+
maxItems: 2,
|
|
46
|
+
description: "Partition ratio range [min, max] along the splitting axis (default: [0.35, 0.65]).",
|
|
47
|
+
},
|
|
48
|
+
colorProbability: {
|
|
49
|
+
type: "number",
|
|
50
|
+
minimum: 0,
|
|
51
|
+
maximum: 1,
|
|
52
|
+
description: "Probability that a leaf cell receives an accent color fill rather than neutral ground (default: 0.35 - 0.45).",
|
|
53
|
+
},
|
|
54
|
+
nestedProbability: {
|
|
55
|
+
type: "number",
|
|
56
|
+
minimum: 0,
|
|
57
|
+
maximum: 1,
|
|
58
|
+
description: "Probability that a colored cell receives an inner nested accent frame (default: 0 - 0.25).",
|
|
59
|
+
},
|
|
60
|
+
dividerWidth: {
|
|
61
|
+
type: "number",
|
|
62
|
+
description: "Stroke thickness in px for orthogonal divider grid lines (e.g. 8 for Mondrian, 1.5 for Swiss, 0 for borderless).",
|
|
63
|
+
},
|
|
64
|
+
dividerColor: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Color of dividing grid lines (hex or rgba, e.g. '#0a0a0a').",
|
|
67
|
+
},
|
|
68
|
+
groundColor: {
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Canvas background / rest color (e.g. '#ffffff' or '#f8fafc').",
|
|
71
|
+
},
|
|
72
|
+
accentColors: {
|
|
73
|
+
type: "array",
|
|
74
|
+
items: { type: "string" },
|
|
75
|
+
description: "List of hex/rgba colors used for cell fills.",
|
|
76
|
+
},
|
|
77
|
+
cellInset: {
|
|
78
|
+
type: "number",
|
|
79
|
+
description: "Inner padding in px inside each cell (default: 0 - 4).",
|
|
80
|
+
},
|
|
81
|
+
bounds: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
x: { type: "number" },
|
|
85
|
+
y: { type: "number" },
|
|
86
|
+
width: { type: "number" },
|
|
87
|
+
height: { type: "number" },
|
|
88
|
+
},
|
|
89
|
+
description: "Bounding box for the subdivision layout (default: full canvas 1280x720 or 1080x1350).",
|
|
90
|
+
},
|
|
91
|
+
seed: {
|
|
92
|
+
type: "integer",
|
|
93
|
+
description: "Deterministic PRNG seed for reproducible composition layouts.",
|
|
94
|
+
},
|
|
95
|
+
idPrefix: {
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "Prefix for generated Paper.js item registry IDs.",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=subdivision-tool-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subdivision-tool-schema.js","sourceRoot":"","sources":["../../../src/vendor/design/subdivision-tool-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH;;;;GAIG;AAYH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL;YACE,IAAI,EAAE,4BAA4B;YAClC,WAAW,EACT,0SAA0S;YAC5S,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;wBAC3D,WAAW,EACT,sPAAsP;qBACzP;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,CAAC;wBACV,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,uGAAuG;qBACrH;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,CAAC;wBACV,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,yEAAyE;qBACvF;oBACD,SAAS,EAAE;wBACT,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,QAAQ,EAAE,CAAC;wBACX,QAAQ,EAAE,CAAC;wBACX,WAAW,EAAE,oFAAoF;qBAClG;oBACD,gBAAgB,EAAE;wBAChB,IAAI,EAAE,QAAQ;wBACd,OAAO,EAAE,CAAC;wBACV,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,+GAA+G;qBAC7H;oBACD,iBAAiB,EAAE;wBACjB,IAAI,EAAE,QAAQ;wBACd,OAAO,EAAE,CAAC;wBACV,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,4FAA4F;qBAC1G;oBACD,YAAY,EAAE;wBACZ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,kHAAkH;qBAChI;oBACD,YAAY,EAAE;wBACZ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,6DAA6D;qBAC3E;oBACD,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,+DAA+D;qBAC7E;oBACD,YAAY,EAAE;wBACZ,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,WAAW,EAAE,8CAA8C;qBAC5D;oBACD,SAAS,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,wDAAwD;qBACtE;oBACD,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACrB,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACrB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACzB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yBAC3B;wBACD,WAAW,EAAE,uFAAuF;qBACrG;oBACD,IAAI,EAAE;wBACJ,IAAI,EAAE,SAAS;wBACf,WAAW,EAAE,+DAA+D;qBAC7E;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,kDAAkD;qBAChE;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|