@extenshi/mcp 0.7.0 → 0.9.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.
Files changed (69) hide show
  1. package/README.md +9 -4
  2. package/dist/bff.d.ts +17 -0
  3. package/dist/bff.d.ts.map +1 -1
  4. package/dist/bff.js +4 -0
  5. package/dist/bff.js.map +1 -1
  6. package/dist/development-guide.d.ts +109 -79
  7. package/dist/development-guide.d.ts.map +1 -1
  8. package/dist/development-guide.js +133 -45
  9. package/dist/development-guide.js.map +1 -1
  10. package/dist/docs.d.ts +45 -4
  11. package/dist/docs.d.ts.map +1 -1
  12. package/dist/docs.js +162 -17
  13. package/dist/docs.js.map +1 -1
  14. package/dist/icon-workflow.d.ts +5 -4
  15. package/dist/icon-workflow.d.ts.map +1 -1
  16. package/dist/icon-workflow.js +33 -32
  17. package/dist/icon-workflow.js.map +1 -1
  18. package/dist/json-ld.d.ts +89 -0
  19. package/dist/json-ld.d.ts.map +1 -0
  20. package/dist/json-ld.js +118 -0
  21. package/dist/json-ld.js.map +1 -0
  22. package/dist/landing-page.d.ts +123 -0
  23. package/dist/landing-page.d.ts.map +1 -0
  24. package/dist/landing-page.js +405 -0
  25. package/dist/landing-page.js.map +1 -0
  26. package/dist/landing-workflow.d.ts +49 -0
  27. package/dist/landing-workflow.d.ts.map +1 -0
  28. package/dist/landing-workflow.js +80 -0
  29. package/dist/landing-workflow.js.map +1 -0
  30. package/dist/localize-workflow.d.ts +6 -1
  31. package/dist/localize-workflow.d.ts.map +1 -1
  32. package/dist/localize-workflow.js +65 -47
  33. package/dist/localize-workflow.js.map +1 -1
  34. package/dist/pay.d.ts +1 -1
  35. package/dist/pay.d.ts.map +1 -1
  36. package/dist/pay.js +11 -11
  37. package/dist/pay.js.map +1 -1
  38. package/dist/privacy-ai-outcome.d.ts +21 -0
  39. package/dist/privacy-ai-outcome.d.ts.map +1 -0
  40. package/dist/privacy-ai-outcome.js +69 -0
  41. package/dist/privacy-ai-outcome.js.map +1 -0
  42. package/dist/scan.d.ts +7 -0
  43. package/dist/scan.d.ts.map +1 -1
  44. package/dist/scan.js +26 -2
  45. package/dist/scan.js.map +1 -1
  46. package/dist/search-filters.js +1 -1
  47. package/dist/search-filters.js.map +1 -1
  48. package/dist/shape.d.ts +34 -0
  49. package/dist/shape.d.ts.map +1 -1
  50. package/dist/shape.js +150 -3
  51. package/dist/shape.js.map +1 -1
  52. package/dist/telemetry.d.ts.map +1 -1
  53. package/dist/telemetry.js +3 -0
  54. package/dist/telemetry.js.map +1 -1
  55. package/dist/templates.js +5 -5
  56. package/dist/templates.js.map +1 -1
  57. package/dist/tools.d.ts +2 -1
  58. package/dist/tools.d.ts.map +1 -1
  59. package/dist/tools.js +398 -115
  60. package/dist/tools.js.map +1 -1
  61. package/dist/welcome-agent-brief.d.ts +9 -9
  62. package/dist/welcome-agent-brief.d.ts.map +1 -1
  63. package/dist/welcome-agent-brief.js +32 -32
  64. package/dist/welcome-agent-brief.js.map +1 -1
  65. package/dist/welcome-workflow.d.ts +5 -5
  66. package/dist/welcome-workflow.d.ts.map +1 -1
  67. package/dist/welcome-workflow.js +13 -14
  68. package/dist/welcome-workflow.js.map +1 -1
  69. package/package.json +3 -2
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Page Generator: an extension's landing / homepage as ONE static HTML file.
3
+ *
4
+ * No JavaScript in the output — pure HTML/CSS, so it deploys anywhere
5
+ * (GitHub Pages, Netlify, S3) and trivially passes CSP. Store CTAs render
6
+ * only for the stores the developer actually filled in.
7
+ *
8
+ * Every user-supplied string is HTML-escaped, every link is scheme-clamped
9
+ * (safeHref: http(s) only; the support link may also be a single mailto:
10
+ * address) and every image source is clamped to https, a
11
+ * relative path or a raster `data:image/…;base64` URL (safeImageSrc). An
12
+ * inline SVG logo is validated (landingLogoSvgProblem) and then embedded
13
+ * through `<img src="data:image/svg+xml,…">`, where browsers never run
14
+ * scripts or fetch external resources — so even a validator miss cannot
15
+ * script the page.
16
+ *
17
+ * SINGLE SOURCE, THREE COPIES:
18
+ * shared-types/landing-page.ts (canonical — edit here; dojo re-exports it)
19
+ * tools/extenshi-mcp/src/landing-page.ts (copy for the published @extenshi/mcp)
20
+ * tools/extenshi-cli/src/landing-page.ts (copy for the published @extenshi/cli)
21
+ * The published packages cannot import workspace shared-types at runtime.
22
+ * The copies differ from this file ONLY in the json-ld import specifier
23
+ * (`./json-ld.js` there, the package specifier here — see
24
+ * module-specifiers.test.ts for why shared-types may not use relative ones).
25
+ * `landing-page-sync.test.ts` in both packages fails when a copy drifts.
26
+ * After editing, run:
27
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-mcp/src/landing-page.ts
28
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-cli/src/landing-page.ts
29
+ */
30
+ export type LandingBrowser = 'chrome' | 'firefox' | 'edge';
31
+ export interface LandingFeature {
32
+ title: string;
33
+ description: string;
34
+ }
35
+ export interface LandingScreenshot {
36
+ /** https URL, or a path relative to the page (e.g. `screenshots/popup.png`). */
37
+ url: string;
38
+ alt: string;
39
+ }
40
+ /**
41
+ * Serializable form persisted as `page-generator` tool state (`{ form }`).
42
+ * The optional fields were added later; rows saved before them still hydrate.
43
+ */
44
+ export interface LandingForm {
45
+ extensionName: string;
46
+ tagline: string;
47
+ description: string;
48
+ accentColor: string;
49
+ theme: 'light' | 'dark';
50
+ chromeUrl: string;
51
+ firefoxUrl: string;
52
+ edgeUrl: string;
53
+ privacyPolicyUrl: string;
54
+ supportUrl: string;
55
+ features: LandingFeature[];
56
+ /** Public https URL the page will live at: canonical link, og:url, JSON-LD url. */
57
+ homepageUrl?: string;
58
+ /** Logo image: https URL, relative path, or `data:image/(png|jpeg|gif|webp);base64,…`. */
59
+ logoUrl?: string;
60
+ /** Inline SVG logo source; wins over logoUrl when it passes validation. */
61
+ logoSvg?: string;
62
+ screenshots?: LandingScreenshot[];
63
+ }
64
+ /** Input limits shared by the MCP tool and CLI schemas. */
65
+ export declare const LANDING_LIMITS: {
66
+ readonly extensionName: 120;
67
+ readonly tagline: 200;
68
+ readonly description: 2000;
69
+ readonly url: 2000;
70
+ readonly features: 12;
71
+ readonly featureTitle: 120;
72
+ readonly featureDescription: 500;
73
+ readonly screenshots: 8;
74
+ readonly screenshotAlt: 200;
75
+ readonly logoSvgBytes: 100000;
76
+ readonly logoUrl: 400000;
77
+ };
78
+ export declare const DEFAULT_LANDING_FORM: LandingForm;
79
+ export interface LandingPageInput {
80
+ extensionName: string;
81
+ tagline: string;
82
+ description: string;
83
+ accentColor: string;
84
+ theme: 'light' | 'dark';
85
+ storeUrls: Partial<Record<LandingBrowser, string>>;
86
+ features: LandingFeature[];
87
+ privacyPolicyUrl: string;
88
+ supportUrl: string;
89
+ /**
90
+ * Optional inline SVG logo. Validated with landingLogoSvgProblem() and
91
+ * embedded as an `<img>` data URI; a rejected SVG falls back to logoUrl,
92
+ * then to a monogram.
93
+ */
94
+ logoSvg?: string;
95
+ logoUrl?: string;
96
+ homepageUrl?: string;
97
+ screenshots?: LandingScreenshot[];
98
+ }
99
+ /**
100
+ * Rebuild the editor form from a saved `page-generator` row (or the project
101
+ * name when nothing is saved). Called during render — not in an effect —
102
+ * so the live preview iframe mounts with this payload, not the empty default.
103
+ * An older row that predates `features` (or the optional fields) still yields
104
+ * a full form.
105
+ */
106
+ export declare function hydrateLandingForm(saved: {
107
+ form?: Partial<LandingForm>;
108
+ } | null | undefined, projectName?: string | null): LandingForm;
109
+ export declare function landingFormToInput(form: LandingForm, logoSvg?: string): LandingPageInput;
110
+ /**
111
+ * Why an inline SVG logo is refused, or null when it is acceptable. A refusal
112
+ * never throws: buildLandingPage falls back to logoUrl / the monogram, and the
113
+ * MCP tool and CLI surface the reason instead of silently dropping the logo.
114
+ */
115
+ export declare function landingLogoSvgProblem(svg: string): string | null;
116
+ /**
117
+ * Human-readable notes about input the page silently corrected (a link clamped
118
+ * to "#", an unsafe image dropped, a refused logo). Same rules as the builder,
119
+ * so agents and the CLI can report exactly what did not make it into the page.
120
+ */
121
+ export declare function landingPageWarnings(input: LandingPageInput): string[];
122
+ export declare function buildLandingPage(input: LandingPageInput): string;
123
+ //# sourceMappingURL=landing-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-page.d.ts","sourceRoot":"","sources":["../src/landing-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;AAE1D,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACX;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAA;CACjC;AAED,2DAA2D;AAC3D,eAAO,MAAM,cAAc;;;;;;;;;;;;CAYjB,CAAA;AAEV,eAAO,MAAM,oBAAoB,EAAE,WAgBlC,CAAA;AAED,MAAM,WAAW,gBAAgB;IAChC,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;IAClD,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAA;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACzD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,WAAW,CAWb;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAgBxF;AA2FD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWhE;AAiBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,EAAE,CA+CrE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAyJhE"}
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Page Generator: an extension's landing / homepage as ONE static HTML file.
3
+ *
4
+ * No JavaScript in the output — pure HTML/CSS, so it deploys anywhere
5
+ * (GitHub Pages, Netlify, S3) and trivially passes CSP. Store CTAs render
6
+ * only for the stores the developer actually filled in.
7
+ *
8
+ * Every user-supplied string is HTML-escaped, every link is scheme-clamped
9
+ * (safeHref: http(s) only; the support link may also be a single mailto:
10
+ * address) and every image source is clamped to https, a
11
+ * relative path or a raster `data:image/…;base64` URL (safeImageSrc). An
12
+ * inline SVG logo is validated (landingLogoSvgProblem) and then embedded
13
+ * through `<img src="data:image/svg+xml,…">`, where browsers never run
14
+ * scripts or fetch external resources — so even a validator miss cannot
15
+ * script the page.
16
+ *
17
+ * SINGLE SOURCE, THREE COPIES:
18
+ * shared-types/landing-page.ts (canonical — edit here; dojo re-exports it)
19
+ * tools/extenshi-mcp/src/landing-page.ts (copy for the published @extenshi/mcp)
20
+ * tools/extenshi-cli/src/landing-page.ts (copy for the published @extenshi/cli)
21
+ * The published packages cannot import workspace shared-types at runtime.
22
+ * The copies differ from this file ONLY in the json-ld import specifier
23
+ * (`./json-ld.js` there, the package specifier here — see
24
+ * module-specifiers.test.ts for why shared-types may not use relative ones).
25
+ * `landing-page-sync.test.ts` in both packages fails when a copy drifts.
26
+ * After editing, run:
27
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-mcp/src/landing-page.ts
28
+ * sed '/^import/s#shared-types/#./#' shared-types/landing-page.ts > tools/extenshi-cli/src/landing-page.ts
29
+ */
30
+ import { jsonLdFromLanding, jsonLdScriptTag } from './json-ld.js';
31
+ /** Input limits shared by the MCP tool and CLI schemas. */
32
+ export const LANDING_LIMITS = {
33
+ extensionName: 120,
34
+ tagline: 200,
35
+ description: 2000,
36
+ url: 2000,
37
+ features: 12,
38
+ featureTitle: 120,
39
+ featureDescription: 500,
40
+ screenshots: 8,
41
+ screenshotAlt: 200,
42
+ logoSvgBytes: 100_000,
43
+ logoUrl: 400_000,
44
+ };
45
+ export const DEFAULT_LANDING_FORM = {
46
+ extensionName: '',
47
+ tagline: '',
48
+ description: '',
49
+ accentColor: '#5e5ce6',
50
+ theme: 'dark',
51
+ chromeUrl: '',
52
+ firefoxUrl: '',
53
+ edgeUrl: '',
54
+ privacyPolicyUrl: '',
55
+ supportUrl: '',
56
+ features: [
57
+ { title: '', description: '' },
58
+ { title: '', description: '' },
59
+ { title: '', description: '' },
60
+ ],
61
+ };
62
+ /**
63
+ * Rebuild the editor form from a saved `page-generator` row (or the project
64
+ * name when nothing is saved). Called during render — not in an effect —
65
+ * so the live preview iframe mounts with this payload, not the empty default.
66
+ * An older row that predates `features` (or the optional fields) still yields
67
+ * a full form.
68
+ */
69
+ export function hydrateLandingForm(saved, projectName) {
70
+ if (saved?.form) {
71
+ const features = Array.isArray(saved.form.features) ? saved.form.features : DEFAULT_LANDING_FORM.features;
72
+ const { screenshots, ...rest } = saved.form;
73
+ const form = { ...DEFAULT_LANDING_FORM, ...rest, features };
74
+ if (Array.isArray(screenshots))
75
+ form.screenshots = screenshots;
76
+ return form;
77
+ }
78
+ const name = projectName?.trim();
79
+ if (name)
80
+ return { ...DEFAULT_LANDING_FORM, extensionName: name };
81
+ return { ...DEFAULT_LANDING_FORM, features: [...DEFAULT_LANDING_FORM.features] };
82
+ }
83
+ export function landingFormToInput(form, logoSvg) {
84
+ return {
85
+ extensionName: form.extensionName,
86
+ tagline: form.tagline,
87
+ description: form.description,
88
+ accentColor: form.accentColor,
89
+ theme: form.theme,
90
+ storeUrls: { chrome: form.chromeUrl, firefox: form.firefoxUrl, edge: form.edgeUrl },
91
+ features: form.features,
92
+ privacyPolicyUrl: form.privacyPolicyUrl,
93
+ supportUrl: form.supportUrl,
94
+ logoSvg: logoSvg ?? form.logoSvg ?? '',
95
+ logoUrl: form.logoUrl ?? '',
96
+ homepageUrl: form.homepageUrl ?? '',
97
+ screenshots: form.screenshots ?? [],
98
+ };
99
+ }
100
+ /** Tolerates non-strings from hand-edited JSON or an old saved row. */
101
+ function str(v) {
102
+ return typeof v === 'string' ? v.trim() : '';
103
+ }
104
+ function esc(s) {
105
+ return s
106
+ .replaceAll('&', '&amp;')
107
+ .replaceAll('<', '&lt;')
108
+ .replaceAll('>', '&gt;')
109
+ .replaceAll('"', '&quot;')
110
+ .replaceAll("'", '&#39;');
111
+ }
112
+ // HTML-escape AND scheme-clamp a user-supplied URL before it lands in an
113
+ // href="". esc() alone stops attribute-breakout but not a `javascript:`/`data:`
114
+ // scheme, so a value like `javascript:alert(1)` would survive into the
115
+ // downloaded page the developer publishes for their own users. Only http(s)
116
+ // URLs are emitted verbatim; anything else collapses to "#".
117
+ function safeHref(raw) {
118
+ const u = raw.trim();
119
+ return /^https?:\/\//i.test(u) ? esc(u) : '#';
120
+ }
121
+ // One plain address, optionally `?subject=` with a percent-encoded value.
122
+ // No `&` (a second header such as bcc/body), no raw or encoded CR/LF, no
123
+ // whitespace, and the address itself admits no `%` — so
124
+ // `mailto:a@b.c%0d%0aBcc:x` and `mailto:javascript:` are both refused.
125
+ const MAILTO = /^mailto:[A-Za-z0-9._+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+(?:\?subject=(?:[A-Za-z0-9._~-]|%(?![01][0-9a-f]|7f)[0-9a-f]{2})+)?$/i;
126
+ /** safeHref() for the support link only: http(s), or a validated mailto: address. */
127
+ function safeSupportHref(raw) {
128
+ const u = raw.trim();
129
+ return MAILTO.test(u) ? esc(u) : safeHref(u);
130
+ }
131
+ const HTTPS_URL = /^https:\/\/[^\s"'<>\\]+$/i;
132
+ const DATA_IMAGE_URL = /^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/;
133
+ // A path relative to the page: no scheme (`javascript:`, `data:`, `http:`), not
134
+ // protocol-relative (`//host`, `\\host` — browsers treat `\` as `/`), and no
135
+ // whitespace or quotes that could smuggle a second attribute.
136
+ const RELATIVE_PATH = /^(?![a-z][a-z0-9+.-]*:)(?![/\\]{2})[^\s"'<>\\]+$/i;
137
+ /** Image src clamp: https, relative path, or raster data URI; '' when unsafe. */
138
+ function safeImageSrc(raw) {
139
+ const u = str(raw);
140
+ if (!u)
141
+ return '';
142
+ if (HTTPS_URL.test(u) || RELATIVE_PATH.test(u))
143
+ return esc(u);
144
+ if (DATA_IMAGE_URL.test(u))
145
+ return u;
146
+ return '';
147
+ }
148
+ function canonicalUrl(raw) {
149
+ const u = str(raw);
150
+ return HTTPS_URL.test(u) ? u : '';
151
+ }
152
+ /** Absolute https form of an image URL (for og:image / JSON-LD), or ''. */
153
+ function absoluteImageUrl(raw, base) {
154
+ const u = str(raw);
155
+ if (HTTPS_URL.test(u))
156
+ return u;
157
+ if (!base || !RELATIVE_PATH.test(u))
158
+ return '';
159
+ try {
160
+ const resolved = new URL(u, base).href;
161
+ return HTTPS_URL.test(resolved) ? resolved : '';
162
+ }
163
+ catch {
164
+ return '';
165
+ }
166
+ }
167
+ const SVG_FORBIDDEN = [
168
+ [/<!DOCTYPE|<!ENTITY/i, 'DOCTYPE/ENTITY declarations are not allowed'],
169
+ [
170
+ /<\s*(script|foreignObject|iframe|object|embed|applet|form|input|textarea|select|button|animate|animateTransform|animateMotion|set|handler|listener)\b/i,
171
+ 'script, foreignObject, embedded documents, form controls and animation elements are not allowed',
172
+ ],
173
+ [/\son[a-z]+\s*=/i, 'event-handler attributes (on*) are not allowed'],
174
+ [/(javascript|vbscript)\s*:/i, 'script URLs are not allowed'],
175
+ [/&#/, 'numeric character references are not allowed'],
176
+ [/@import|expression\s*\(/i, 'CSS @import / expression() is not allowed'],
177
+ [
178
+ // Quote handled by alternation, not `["']?`, so backtracking cannot skip
179
+ // the quote and let `(?!#)` look at it instead of the value.
180
+ /\s(?:xlink:)?href\s*=\s*(?:"\s*|'\s*|)(?!["'#\s]|data:image\/(?:png|jpeg|gif|webp);)/i,
181
+ 'href values other than #fragments or raster data: images are not allowed',
182
+ ],
183
+ ];
184
+ /**
185
+ * Why an inline SVG logo is refused, or null when it is acceptable. A refusal
186
+ * never throws: buildLandingPage falls back to logoUrl / the monogram, and the
187
+ * MCP tool and CLI surface the reason instead of silently dropping the logo.
188
+ */
189
+ export function landingLogoSvgProblem(svg) {
190
+ const s = str(svg);
191
+ if (!s)
192
+ return 'the SVG is empty';
193
+ if (new TextEncoder().encode(s).length > LANDING_LIMITS.logoSvgBytes) {
194
+ return `the SVG exceeds ${LANDING_LIMITS.logoSvgBytes} bytes`;
195
+ }
196
+ if (!/^(?:<\?xml[^>]*\?>\s*)?(?:<!--[\s\S]*?-->\s*)*<svg[\s>]/i.test(s) || !/<\/svg>$/i.test(s)) {
197
+ return 'the logo is not a single <svg>…</svg> document';
198
+ }
199
+ for (const [pattern, reason] of SVG_FORBIDDEN)
200
+ if (pattern.test(s))
201
+ return reason;
202
+ return null;
203
+ }
204
+ const BROWSER_LABELS = {
205
+ chrome: 'Google Chrome',
206
+ firefox: 'Mozilla Firefox',
207
+ edge: 'Microsoft Edge',
208
+ };
209
+ const STORE_CTA_LABELS = {
210
+ chrome: 'Add to Chrome',
211
+ firefox: 'Get for Firefox',
212
+ edge: 'Get for Edge',
213
+ };
214
+ const DEFAULT_ACCENT = '#5e5ce6';
215
+ const HEX_COLOR = /^#[0-9a-fA-F]{3,8}$/;
216
+ /**
217
+ * Human-readable notes about input the page silently corrected (a link clamped
218
+ * to "#", an unsafe image dropped, a refused logo). Same rules as the builder,
219
+ * so agents and the CLI can report exactly what did not make it into the page.
220
+ */
221
+ export function landingPageWarnings(input) {
222
+ const out = [];
223
+ const links = [
224
+ ['chromeUrl', input.storeUrls.chrome],
225
+ ['firefoxUrl', input.storeUrls.firefox],
226
+ ['edgeUrl', input.storeUrls.edge],
227
+ ['privacyPolicyUrl', input.privacyPolicyUrl],
228
+ ];
229
+ for (const [field, value] of links) {
230
+ const v = str(value);
231
+ if (v && safeHref(v) === '#')
232
+ out.push(`${field} is not an http(s) URL; its link points to "#".`);
233
+ }
234
+ const support = str(input.supportUrl);
235
+ if (support && safeSupportHref(support) === '#') {
236
+ out.push('supportUrl is not an http(s) URL or a single mailto: address; its link points to "#".');
237
+ }
238
+ if (!Object.keys(STORE_CTA_LABELS).some((b) => str(input.storeUrls[b]))) {
239
+ out.push('No store URL is set, so the page has no install button.');
240
+ }
241
+ if (str(input.accentColor) && !HEX_COLOR.test(str(input.accentColor))) {
242
+ out.push(`accentColor is not a hex colour; ${DEFAULT_ACCENT} is used.`);
243
+ }
244
+ const homepage = canonicalUrl(input.homepageUrl);
245
+ if (str(input.homepageUrl) && !homepage) {
246
+ out.push('homepageUrl is not an https URL; canonical, og:url and JSON-LD url are omitted.');
247
+ }
248
+ const svg = str(input.logoSvg);
249
+ const svgProblem = svg ? landingLogoSvgProblem(svg) : null;
250
+ if (svgProblem)
251
+ out.push(`logoSvg was refused (${svgProblem}); the fallback logo is shown.`);
252
+ if (str(input.logoUrl) && !safeImageSrc(input.logoUrl)) {
253
+ out.push('logoUrl is not an https URL, relative path or raster data: image; it is omitted.');
254
+ }
255
+ const shots = Array.isArray(input.screenshots) ? input.screenshots : [];
256
+ let relativeShots = 0;
257
+ for (const [i, shot] of shots.slice(0, LANDING_LIMITS.screenshots).entries()) {
258
+ const url = str(shot?.url);
259
+ if (!safeImageSrc(url))
260
+ out.push(`screenshots[${i}].url is not an https URL or relative path; it is omitted.`);
261
+ else if (!HTTPS_URL.test(url) && !DATA_IMAGE_URL.test(url))
262
+ relativeShots++;
263
+ }
264
+ if (shots.length > LANDING_LIMITS.screenshots) {
265
+ out.push(`Only the first ${LANDING_LIMITS.screenshots} screenshots are used.`);
266
+ }
267
+ if (relativeShots > 0 && !homepage) {
268
+ out.push('Relative screenshot paths need an https homepageUrl to appear in og:image and JSON-LD.');
269
+ }
270
+ return out;
271
+ }
272
+ export function buildLandingPage(input) {
273
+ const rawName = str(input.extensionName) || 'My Extension';
274
+ const name = esc(rawName);
275
+ const tagline = esc(str(input.tagline));
276
+ const description = str(input.description);
277
+ const accent = HEX_COLOR.test(str(input.accentColor)) ? str(input.accentColor) : DEFAULT_ACCENT;
278
+ const dark = input.theme === 'dark';
279
+ const bg = dark ? '#0f1115' : '#ffffff';
280
+ const fg = dark ? '#e8eaf0' : '#1f2430';
281
+ const muted = dark ? '#9aa1b2' : '#5b6372';
282
+ const cardBg = dark ? '#171a21' : '#f6f7fa';
283
+ const border = dark ? '#262b36' : '#e5e8ef';
284
+ const homepage = canonicalUrl(input.homepageUrl);
285
+ const monogram = rawName.charAt(0).toUpperCase() || 'E';
286
+ const svg = str(input.logoSvg);
287
+ const logoSrc = svg && !landingLogoSvgProblem(svg)
288
+ ? `data:image/svg+xml,${encodeURIComponent(svg)}`
289
+ : safeImageSrc(input.logoUrl);
290
+ const logo = logoSrc
291
+ ? `<div class="logo"><img src="${logoSrc}" alt="${name} logo" width="64" height="64" /></div>`
292
+ : `<div class="logo monogram" aria-hidden="true">${esc(monogram)}</div>`;
293
+ const ctas = Object.keys(STORE_CTA_LABELS)
294
+ .filter((b) => str(input.storeUrls[b]))
295
+ .map((b) => `<a class="cta${b === 'chrome' ? ' primary' : ''}" href="${safeHref(str(input.storeUrls[b]))}" rel="noopener">${STORE_CTA_LABELS[b]}<span class="cta-sub">${esc(BROWSER_LABELS[b])}</span></a>`)
296
+ .join('\n\t\t\t');
297
+ const featureList = Array.isArray(input.features) ? input.features : [];
298
+ const features = featureList
299
+ .filter((f) => str(f?.title))
300
+ .map((f) => `<div class="feature">
301
+ <h3>${esc(str(f.title))}</h3>
302
+ <p>${esc(str(f.description))}</p>
303
+ </div>`)
304
+ .join('\n\t\t\t');
305
+ const shots = (Array.isArray(input.screenshots) ? input.screenshots : [])
306
+ .slice(0, LANDING_LIMITS.screenshots)
307
+ .map((shot, i) => ({
308
+ url: str(shot?.url),
309
+ src: safeImageSrc(shot?.url),
310
+ alt: str(shot?.alt).slice(0, LANDING_LIMITS.screenshotAlt) || `${rawName} screenshot ${i + 1}`,
311
+ }))
312
+ .filter((shot) => shot.src);
313
+ const screenshots = shots
314
+ .map((shot) => `<figure class="shot"><img src="${shot.src}" alt="${esc(shot.alt)}" loading="lazy" /></figure>`)
315
+ .join('\n\t\t\t');
316
+ const absoluteShots = shots.map((shot) => absoluteImageUrl(shot.url, homepage)).filter(Boolean);
317
+ const footerLinks = [];
318
+ if (str(input.privacyPolicyUrl)) {
319
+ footerLinks.push(`<a href="${safeHref(str(input.privacyPolicyUrl))}">Privacy policy</a>`);
320
+ }
321
+ if (str(input.supportUrl)) {
322
+ footerLinks.push(`<a href="${safeSupportHref(str(input.supportUrl))}">Support</a>`);
323
+ }
324
+ const jsonLd = jsonLdScriptTag(jsonLdFromLanding({
325
+ extensionName: rawName,
326
+ tagline: str(input.tagline),
327
+ description,
328
+ storeUrls: input.storeUrls,
329
+ features: featureList
330
+ .filter((f) => str(f?.title))
331
+ .map((f) => ({ title: str(f.title), description: str(f.description) })),
332
+ privacyPolicyUrl: str(input.privacyPolicyUrl),
333
+ homepageUrl: homepage || undefined,
334
+ screenshots: absoluteShots,
335
+ }));
336
+ const metaDescription = esc(description || str(input.tagline));
337
+ const ogImage = absoluteShots[0] ?? '';
338
+ const head = [
339
+ `<title>${name}${tagline ? ` — ${tagline}` : ''}</title>`,
340
+ `<meta name="description" content="${metaDescription}" />`,
341
+ homepage ? `<link rel="canonical" href="${esc(homepage)}" />` : '',
342
+ '<meta property="og:type" content="website" />',
343
+ `<meta property="og:title" content="${name}" />`,
344
+ metaDescription ? `<meta property="og:description" content="${metaDescription}" />` : '',
345
+ homepage ? `<meta property="og:url" content="${esc(homepage)}" />` : '',
346
+ ogImage ? `<meta property="og:image" content="${esc(ogImage)}" />` : '',
347
+ `<meta name="twitter:card" content="${ogImage ? 'summary_large_image' : 'summary'}" />`,
348
+ jsonLd,
349
+ ]
350
+ .filter(Boolean)
351
+ .join('\n');
352
+ return `<!doctype html>
353
+ <html lang="en">
354
+ <head>
355
+ <meta charset="utf-8" />
356
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
357
+ ${head}
358
+ <style>
359
+ * { box-sizing: border-box; margin: 0; padding: 0; }
360
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: ${bg}; color: ${fg}; line-height: 1.6; }
361
+ .wrap { max-width: 880px; margin: 0 auto; padding: 0 24px; }
362
+ header { padding: 88px 0 56px; text-align: center; }
363
+ .logo { width: 88px; height: 88px; margin: 0 auto 28px; border-radius: 22px; display: flex; align-items: center; justify-content: center; background: ${cardBg}; border: 1px solid ${border}; overflow: hidden; }
364
+ .logo img { width: 64px; height: 64px; object-fit: contain; }
365
+ .logo.monogram { font-size: 2.4rem; font-weight: 700; color: ${accent}; }
366
+ h1 { font-size: 2.6rem; letter-spacing: -0.02em; line-height: 1.15; }
367
+ .tagline { margin-top: 14px; font-size: 1.25rem; color: ${muted}; }
368
+ .ctas { margin-top: 36px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
369
+ .cta { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; padding: 12px 26px; border-radius: 12px; border: 1px solid ${border}; background: ${cardBg}; color: ${fg}; text-decoration: none; font-weight: 600; transition: transform 0.12s ease; }
370
+ .cta:hover { transform: translateY(-2px); }
371
+ .cta.primary { background: ${accent}; border-color: ${accent}; color: #fff; }
372
+ .cta-sub { font-size: 0.72rem; font-weight: 400; opacity: 0.75; }
373
+ .about { padding: 8px 0 24px; text-align: center; }
374
+ .about p { max-width: 640px; margin: 0 auto; color: ${muted}; }
375
+ .shots { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; padding: 24px 0 8px; }
376
+ .shot img { display: block; width: 100%; height: auto; border-radius: 12px; border: 1px solid ${border}; }
377
+ .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; padding: 40px 0 64px; }
378
+ .feature { background: ${cardBg}; border: 1px solid ${border}; border-radius: 14px; padding: 22px; }
379
+ .feature h3 { font-size: 1.02rem; margin-bottom: 8px; }
380
+ .feature p { font-size: 0.92rem; color: ${muted}; }
381
+ footer { border-top: 1px solid ${border}; padding: 28px 0 48px; text-align: center; font-size: 0.85rem; color: ${muted}; }
382
+ footer a { color: ${muted}; margin: 0 10px; }
383
+ </style>
384
+ </head>
385
+ <body>
386
+ <div class="wrap">
387
+ <header>
388
+ ${logo}
389
+ <h1>${name}</h1>
390
+ ${tagline ? `<p class="tagline">${tagline}</p>` : ''}
391
+ ${ctas ? `<div class="ctas">\n\t\t\t${ctas}\n\t\t\t</div>` : ''}
392
+ </header>
393
+ ${description ? `<section class="about"><p>${esc(description)}</p></section>` : ''}
394
+ ${screenshots ? `<section class="shots">\n\t\t\t${screenshots}\n\t\t</section>` : ''}
395
+ ${features ? `<section class="features">\n\t\t\t${features}\n\t\t</section>` : ''}
396
+ <footer>
397
+ ${footerLinks.join('\n\t\t\t')}
398
+ <div>© ${name}</div>
399
+ </footer>
400
+ </div>
401
+ </body>
402
+ </html>
403
+ `;
404
+ }
405
+ //# sourceMappingURL=landing-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-page.js","sourceRoot":"","sources":["../src/landing-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Body of the free `generate_landing_page` MCP tool.
3
+ *
4
+ * Pure function of its arguments — no API key, no network, no credits — so it
5
+ * is registered under the `docs` capability and works on both the local stdio
6
+ * server and the hosted connector. The HTML comes from ./landing-page.ts, a
7
+ * synced copy of shared-types/landing-page.ts: the page an agent generates here
8
+ * is byte-for-byte what the cabinet Page generator downloads for the same form.
9
+ *
10
+ * Extenshi does not host the page. The returned `nextSteps` describe hosting it
11
+ * on any HTTPS origin and registering the URL with `upsert_hosted_page`, which
12
+ * is what feeds HOMEPAGE_URL in the generated integration config.
13
+ */
14
+ import { type LandingForm } from './landing-page.js';
15
+ export interface LandingPageArgs {
16
+ extensionName: string;
17
+ tagline?: string;
18
+ description?: string;
19
+ accentColor?: string;
20
+ theme?: 'light' | 'dark';
21
+ chromeUrl?: string;
22
+ firefoxUrl?: string;
23
+ edgeUrl?: string;
24
+ privacyPolicyUrl?: string;
25
+ supportUrl?: string;
26
+ homepageUrl?: string;
27
+ features?: {
28
+ title: string;
29
+ description?: string;
30
+ }[];
31
+ screenshots?: {
32
+ url: string;
33
+ alt?: string;
34
+ }[];
35
+ logoSvg?: string;
36
+ logoUrl?: string;
37
+ }
38
+ export interface GeneratedLandingPage {
39
+ html: string;
40
+ bytes: number;
41
+ warnings: string[];
42
+ nextSteps: string[];
43
+ }
44
+ export declare function landingFormFromArgs(args: LandingPageArgs): LandingForm;
45
+ export declare function landingNextSteps(homepageUrl?: string): string[];
46
+ export declare function renderGenerateLandingPage(args: LandingPageArgs): GeneratedLandingPage;
47
+ /** Follow-ups after publish_landing_page, from the fields the BFF returned. */
48
+ export declare function hostedLandingNextSteps(result: Record<string, unknown>): string[];
49
+ //# sourceMappingURL=landing-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing-workflow.d.ts","sourceRoot":"","sources":["../src/landing-workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAGN,KAAK,WAAW,EAIhB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,eAAe;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACpD,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAsBtE;AAED,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,eAAe,GAAG,oBAAoB,CAWrF;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAehF"}