@framers/agentos-ext-widget-generator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/dist/WidgetFileManager.d.ts +132 -0
- package/dist/WidgetFileManager.d.ts.map +1 -0
- package/dist/WidgetFileManager.js +178 -0
- package/dist/WidgetFileManager.js.map +1 -0
- package/dist/WidgetWrapper.d.ts +65 -0
- package/dist/WidgetWrapper.d.ts.map +1 -0
- package/dist/WidgetWrapper.js +117 -0
- package/dist/WidgetWrapper.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/generateWidget.d.ts +78 -0
- package/dist/tools/generateWidget.d.ts.map +1 -0
- package/dist/tools/generateWidget.js +144 -0
- package/dist/tools/generateWidget.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/manifest.json +26 -0
- package/package.json +65 -0
- package/src/WidgetFileManager.ts +222 -0
- package/src/WidgetWrapper.ts +134 -0
- package/src/index.ts +91 -0
- package/src/tools/generateWidget.ts +178 -0
- package/src/types.ts +50 -0
- package/tsconfig.json +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Framers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module WidgetFileManager
|
|
3
|
+
*
|
|
4
|
+
* Manages the local widgets directory for generated HTML widgets. Provides
|
|
5
|
+
* methods to save widget HTML to disk, list existing widgets, delete files,
|
|
6
|
+
* resolve full paths, and construct view/download URLs.
|
|
7
|
+
*
|
|
8
|
+
* Files are stored under `{workspaceDir}/widgets/` with timestamped,
|
|
9
|
+
* slugified filenames to avoid collisions and ensure filesystem safety.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Metadata returned when listing files in the widgets directory.
|
|
13
|
+
*/
|
|
14
|
+
export interface WidgetFileEntry {
|
|
15
|
+
/** The file's base name (e.g. `2026-03-28T12-00-00-000Z-my-widget.html`). */
|
|
16
|
+
filename: string;
|
|
17
|
+
/** File size in bytes. */
|
|
18
|
+
sizeBytes: number;
|
|
19
|
+
/** ISO 8601 timestamp of when the file was created (from filesystem). */
|
|
20
|
+
createdAt: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result returned after successfully saving a widget to disk.
|
|
24
|
+
*/
|
|
25
|
+
export interface WidgetSaveResult {
|
|
26
|
+
/** Absolute path to the saved file. */
|
|
27
|
+
filePath: string;
|
|
28
|
+
/** The generated filename (basename only). */
|
|
29
|
+
filename: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Manages the widgets directory for generated HTML widgets. Handles saving,
|
|
33
|
+
* listing, deleting, and resolving paths for widget files.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const manager = new WidgetFileManager('/home/agent/workspace', 3777);
|
|
38
|
+
* const { filePath, filename } = await manager.save('<html>...</html>', 'My Chart');
|
|
39
|
+
* const url = manager.getWidgetUrl(filename);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class WidgetFileManager {
|
|
43
|
+
/** Absolute path to the widgets directory. */
|
|
44
|
+
private readonly widgetsDir;
|
|
45
|
+
/** Port used for constructing view and download URLs. */
|
|
46
|
+
private readonly serverPort;
|
|
47
|
+
/**
|
|
48
|
+
* Create a new WidgetFileManager instance.
|
|
49
|
+
*
|
|
50
|
+
* @param workspaceDir - Root workspace directory for the agent. The
|
|
51
|
+
* widgets directory will be created as a subdirectory named `widgets`.
|
|
52
|
+
* @param serverPort - Optional port number for constructing localhost
|
|
53
|
+
* view and download URLs. Defaults to `3777`.
|
|
54
|
+
*/
|
|
55
|
+
constructor(workspaceDir: string, serverPort?: number);
|
|
56
|
+
/**
|
|
57
|
+
* Save an HTML widget to the widgets directory.
|
|
58
|
+
*
|
|
59
|
+
* Creates the widgets directory if it does not already exist. The filename
|
|
60
|
+
* is generated from the current ISO timestamp and a slugified version of
|
|
61
|
+
* the widget title, ensuring uniqueness and filesystem safety.
|
|
62
|
+
*
|
|
63
|
+
* @param html - The complete HTML content to write.
|
|
64
|
+
* @param title - The widget title, used to derive the filename slug.
|
|
65
|
+
* @returns An object containing the absolute `filePath` and `filename`.
|
|
66
|
+
*/
|
|
67
|
+
save(html: string, title: string): Promise<WidgetSaveResult>;
|
|
68
|
+
/**
|
|
69
|
+
* List all widget files in the widgets directory with their metadata.
|
|
70
|
+
*
|
|
71
|
+
* Returns an empty array if the widgets directory does not exist or
|
|
72
|
+
* contains no files. Non-file entries (directories, symlinks) are
|
|
73
|
+
* silently skipped.
|
|
74
|
+
*
|
|
75
|
+
* @returns An array of {@link WidgetFileEntry} objects sorted by filename
|
|
76
|
+
* (newest first due to the timestamp prefix convention).
|
|
77
|
+
*/
|
|
78
|
+
list(): Promise<WidgetFileEntry[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Remove a widget file from the widgets directory.
|
|
81
|
+
*
|
|
82
|
+
* @param filename - The basename of the file to delete.
|
|
83
|
+
* @returns `true` if the file was successfully deleted, `false` if it
|
|
84
|
+
* did not exist or could not be removed.
|
|
85
|
+
*/
|
|
86
|
+
remove(filename: string): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve a filename to its absolute path in the widgets directory.
|
|
89
|
+
*
|
|
90
|
+
* @param filename - The basename of the file to resolve.
|
|
91
|
+
* @returns The absolute file path if the file exists, or `null` if not found.
|
|
92
|
+
*/
|
|
93
|
+
resolve(filename: string): string | null;
|
|
94
|
+
/**
|
|
95
|
+
* Construct a view URL for the given widget filename.
|
|
96
|
+
*
|
|
97
|
+
* Uses the configured server port to build a localhost URL. In
|
|
98
|
+
* production deployments the URL scheme would be replaced by a
|
|
99
|
+
* reverse-proxy or CDN URL.
|
|
100
|
+
*
|
|
101
|
+
* @param filename - The basename of the widget file.
|
|
102
|
+
* @returns A fully-qualified HTTP URL pointing to the widget.
|
|
103
|
+
*/
|
|
104
|
+
getWidgetUrl(filename: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Construct a download URL for the given widget filename.
|
|
107
|
+
*
|
|
108
|
+
* Returns the same URL as {@link getWidgetUrl} since the widget is
|
|
109
|
+
* a self-contained HTML file that can be both viewed and downloaded.
|
|
110
|
+
*
|
|
111
|
+
* @param filename - The basename of the widget file.
|
|
112
|
+
* @returns A fully-qualified HTTP URL pointing to the file.
|
|
113
|
+
*/
|
|
114
|
+
getDownloadUrl(filename: string): string;
|
|
115
|
+
/**
|
|
116
|
+
* Convert a title string into a URL- and filesystem-safe slug.
|
|
117
|
+
*
|
|
118
|
+
* Transforms the input to lowercase, replaces non-alphanumeric
|
|
119
|
+
* characters with hyphens, collapses consecutive hyphens, and trims
|
|
120
|
+
* leading/trailing hyphens.
|
|
121
|
+
*
|
|
122
|
+
* @param title - The raw title string to slugify.
|
|
123
|
+
* @returns A clean, lowercase slug suitable for filenames.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* slugify('3D Solar System!') // '3d-solar-system'
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
private slugify;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=WidgetFileManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetFileManager.d.ts","sourceRoot":"","sources":["../src/WidgetFileManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IAEjB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAElB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IAEjB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAiB;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC;;;;;;;OAOG;gBACS,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAKrD;;;;;;;;;;OAUG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAelE;;;;;;;;;OASG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAgCxC;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAehD;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKxC;;;;;;;;;OASG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAItC;;;;;;;;OAQG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIxC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,OAAO;CAOhB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module WidgetFileManager
|
|
3
|
+
*
|
|
4
|
+
* Manages the local widgets directory for generated HTML widgets. Provides
|
|
5
|
+
* methods to save widget HTML to disk, list existing widgets, delete files,
|
|
6
|
+
* resolve full paths, and construct view/download URLs.
|
|
7
|
+
*
|
|
8
|
+
* Files are stored under `{workspaceDir}/widgets/` with timestamped,
|
|
9
|
+
* slugified filenames to avoid collisions and ensure filesystem safety.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdir, writeFile, readdir, stat, unlink } from 'node:fs/promises';
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
/**
|
|
15
|
+
* Manages the widgets directory for generated HTML widgets. Handles saving,
|
|
16
|
+
* listing, deleting, and resolving paths for widget files.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const manager = new WidgetFileManager('/home/agent/workspace', 3777);
|
|
21
|
+
* const { filePath, filename } = await manager.save('<html>...</html>', 'My Chart');
|
|
22
|
+
* const url = manager.getWidgetUrl(filename);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class WidgetFileManager {
|
|
26
|
+
/** Absolute path to the widgets directory. */
|
|
27
|
+
widgetsDir;
|
|
28
|
+
/** Port used for constructing view and download URLs. */
|
|
29
|
+
serverPort;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new WidgetFileManager instance.
|
|
32
|
+
*
|
|
33
|
+
* @param workspaceDir - Root workspace directory for the agent. The
|
|
34
|
+
* widgets directory will be created as a subdirectory named `widgets`.
|
|
35
|
+
* @param serverPort - Optional port number for constructing localhost
|
|
36
|
+
* view and download URLs. Defaults to `3777`.
|
|
37
|
+
*/
|
|
38
|
+
constructor(workspaceDir, serverPort) {
|
|
39
|
+
this.widgetsDir = join(workspaceDir, 'widgets');
|
|
40
|
+
this.serverPort = serverPort ?? 3777;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Save an HTML widget to the widgets directory.
|
|
44
|
+
*
|
|
45
|
+
* Creates the widgets directory if it does not already exist. The filename
|
|
46
|
+
* is generated from the current ISO timestamp and a slugified version of
|
|
47
|
+
* the widget title, ensuring uniqueness and filesystem safety.
|
|
48
|
+
*
|
|
49
|
+
* @param html - The complete HTML content to write.
|
|
50
|
+
* @param title - The widget title, used to derive the filename slug.
|
|
51
|
+
* @returns An object containing the absolute `filePath` and `filename`.
|
|
52
|
+
*/
|
|
53
|
+
async save(html, title) {
|
|
54
|
+
if (!existsSync(this.widgetsDir)) {
|
|
55
|
+
await mkdir(this.widgetsDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
58
|
+
const slug = this.slugify(title);
|
|
59
|
+
const filename = `${timestamp}-${slug}.html`;
|
|
60
|
+
const filePath = join(this.widgetsDir, filename);
|
|
61
|
+
await writeFile(filePath, html, 'utf-8');
|
|
62
|
+
return { filePath, filename };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List all widget files in the widgets directory with their metadata.
|
|
66
|
+
*
|
|
67
|
+
* Returns an empty array if the widgets directory does not exist or
|
|
68
|
+
* contains no files. Non-file entries (directories, symlinks) are
|
|
69
|
+
* silently skipped.
|
|
70
|
+
*
|
|
71
|
+
* @returns An array of {@link WidgetFileEntry} objects sorted by filename
|
|
72
|
+
* (newest first due to the timestamp prefix convention).
|
|
73
|
+
*/
|
|
74
|
+
async list() {
|
|
75
|
+
if (!existsSync(this.widgetsDir)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const entries = await readdir(this.widgetsDir);
|
|
79
|
+
const results = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
const fullPath = join(this.widgetsDir, entry);
|
|
82
|
+
try {
|
|
83
|
+
const fileStat = await stat(fullPath);
|
|
84
|
+
if (!fileStat.isFile()) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
results.push({
|
|
88
|
+
filename: entry,
|
|
89
|
+
sizeBytes: fileStat.size,
|
|
90
|
+
createdAt: fileStat.birthtime.toISOString(),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Skip files that can't be stat'd (e.g. permission errors)
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Remove a widget file from the widgets directory.
|
|
102
|
+
*
|
|
103
|
+
* @param filename - The basename of the file to delete.
|
|
104
|
+
* @returns `true` if the file was successfully deleted, `false` if it
|
|
105
|
+
* did not exist or could not be removed.
|
|
106
|
+
*/
|
|
107
|
+
async remove(filename) {
|
|
108
|
+
const fullPath = join(this.widgetsDir, filename);
|
|
109
|
+
if (!existsSync(fullPath)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await unlink(fullPath);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a filename to its absolute path in the widgets directory.
|
|
122
|
+
*
|
|
123
|
+
* @param filename - The basename of the file to resolve.
|
|
124
|
+
* @returns The absolute file path if the file exists, or `null` if not found.
|
|
125
|
+
*/
|
|
126
|
+
resolve(filename) {
|
|
127
|
+
const fullPath = join(this.widgetsDir, filename);
|
|
128
|
+
return existsSync(fullPath) ? fullPath : null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Construct a view URL for the given widget filename.
|
|
132
|
+
*
|
|
133
|
+
* Uses the configured server port to build a localhost URL. In
|
|
134
|
+
* production deployments the URL scheme would be replaced by a
|
|
135
|
+
* reverse-proxy or CDN URL.
|
|
136
|
+
*
|
|
137
|
+
* @param filename - The basename of the widget file.
|
|
138
|
+
* @returns A fully-qualified HTTP URL pointing to the widget.
|
|
139
|
+
*/
|
|
140
|
+
getWidgetUrl(filename) {
|
|
141
|
+
return `http://localhost:${this.serverPort}/widgets/${filename}`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Construct a download URL for the given widget filename.
|
|
145
|
+
*
|
|
146
|
+
* Returns the same URL as {@link getWidgetUrl} since the widget is
|
|
147
|
+
* a self-contained HTML file that can be both viewed and downloaded.
|
|
148
|
+
*
|
|
149
|
+
* @param filename - The basename of the widget file.
|
|
150
|
+
* @returns A fully-qualified HTTP URL pointing to the file.
|
|
151
|
+
*/
|
|
152
|
+
getDownloadUrl(filename) {
|
|
153
|
+
return `http://localhost:${this.serverPort}/widgets/${filename}`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Convert a title string into a URL- and filesystem-safe slug.
|
|
157
|
+
*
|
|
158
|
+
* Transforms the input to lowercase, replaces non-alphanumeric
|
|
159
|
+
* characters with hyphens, collapses consecutive hyphens, and trims
|
|
160
|
+
* leading/trailing hyphens.
|
|
161
|
+
*
|
|
162
|
+
* @param title - The raw title string to slugify.
|
|
163
|
+
* @returns A clean, lowercase slug suitable for filenames.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* slugify('3D Solar System!') // '3d-solar-system'
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
slugify(title) {
|
|
171
|
+
return title
|
|
172
|
+
.toLowerCase()
|
|
173
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
174
|
+
.replace(/-+/g, '-')
|
|
175
|
+
.replace(/^-|-$/g, '');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=WidgetFileManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetFileManager.js","sourceRoot":"","sources":["../src/WidgetFileManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module WidgetWrapper
|
|
3
|
+
*
|
|
4
|
+
* Safety wrapper that ensures every generated widget has a well-formed
|
|
5
|
+
* HTML structure, sensible defaults, and a client-side error boundary.
|
|
6
|
+
*
|
|
7
|
+
* The wrapper is additive: it inspects the incoming HTML with
|
|
8
|
+
* case-insensitive matching and only injects elements that are missing.
|
|
9
|
+
* This prevents double-adding when the agent already includes a
|
|
10
|
+
* doctype, charset meta, viewport meta, or error handler.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Wraps raw HTML content with structural defaults and an error boundary.
|
|
14
|
+
*
|
|
15
|
+
* Guarantees that every widget has:
|
|
16
|
+
* - A `<!DOCTYPE html>` declaration
|
|
17
|
+
* - A `<meta charset="utf-8">` tag
|
|
18
|
+
* - A responsive viewport meta tag
|
|
19
|
+
* - A minimal CSS reset (margin/padding/box-sizing + system-ui font)
|
|
20
|
+
* - A `window.onerror` error boundary that surfaces runtime errors visually
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const wrapper = new WidgetWrapper();
|
|
25
|
+
* const safe = wrapper.wrap('<div>Hello world</div>');
|
|
26
|
+
* // safe now contains a full HTML document with all defaults injected
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class WidgetWrapper {
|
|
30
|
+
/**
|
|
31
|
+
* Apply the safety wrapper to the given HTML string.
|
|
32
|
+
*
|
|
33
|
+
* Performs case-insensitive checks against the source HTML and only
|
|
34
|
+
* injects elements that are not already present. The injection order
|
|
35
|
+
* is: doctype, charset, viewport, CSS reset, error boundary.
|
|
36
|
+
*
|
|
37
|
+
* @param html - Raw HTML content to wrap.
|
|
38
|
+
* @returns The wrapped HTML with all missing defaults injected.
|
|
39
|
+
*/
|
|
40
|
+
wrap(html: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Inject content into the `<head>` section of the HTML document.
|
|
43
|
+
*
|
|
44
|
+
* If a `<head>` tag exists, the content is inserted right after it.
|
|
45
|
+
* Otherwise, it is prepended to the document (after the doctype, if
|
|
46
|
+
* present).
|
|
47
|
+
*
|
|
48
|
+
* @param html - The HTML document string.
|
|
49
|
+
* @param content - The HTML fragment to inject.
|
|
50
|
+
* @returns The modified HTML with the content injected.
|
|
51
|
+
*/
|
|
52
|
+
private injectIntoHead;
|
|
53
|
+
/**
|
|
54
|
+
* Inject content just before the closing `</body>` tag.
|
|
55
|
+
*
|
|
56
|
+
* If no `</body>` tag exists, the content is appended at the end
|
|
57
|
+
* of the document.
|
|
58
|
+
*
|
|
59
|
+
* @param html - The HTML document string.
|
|
60
|
+
* @param content - The HTML fragment to inject.
|
|
61
|
+
* @returns The modified HTML with the content injected.
|
|
62
|
+
*/
|
|
63
|
+
private injectBeforeBodyClose;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=WidgetWrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetWrapper.d.ts","sourceRoot":"","sources":["../src/WidgetWrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;OASG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA6C1B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,cAAc;IAkBtB;;;;;;;;;OASG;IACH,OAAO,CAAC,qBAAqB;CAS9B"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module WidgetWrapper
|
|
3
|
+
*
|
|
4
|
+
* Safety wrapper that ensures every generated widget has a well-formed
|
|
5
|
+
* HTML structure, sensible defaults, and a client-side error boundary.
|
|
6
|
+
*
|
|
7
|
+
* The wrapper is additive: it inspects the incoming HTML with
|
|
8
|
+
* case-insensitive matching and only injects elements that are missing.
|
|
9
|
+
* This prevents double-adding when the agent already includes a
|
|
10
|
+
* doctype, charset meta, viewport meta, or error handler.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Wraps raw HTML content with structural defaults and an error boundary.
|
|
14
|
+
*
|
|
15
|
+
* Guarantees that every widget has:
|
|
16
|
+
* - A `<!DOCTYPE html>` declaration
|
|
17
|
+
* - A `<meta charset="utf-8">` tag
|
|
18
|
+
* - A responsive viewport meta tag
|
|
19
|
+
* - A minimal CSS reset (margin/padding/box-sizing + system-ui font)
|
|
20
|
+
* - A `window.onerror` error boundary that surfaces runtime errors visually
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const wrapper = new WidgetWrapper();
|
|
25
|
+
* const safe = wrapper.wrap('<div>Hello world</div>');
|
|
26
|
+
* // safe now contains a full HTML document with all defaults injected
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class WidgetWrapper {
|
|
30
|
+
/**
|
|
31
|
+
* Apply the safety wrapper to the given HTML string.
|
|
32
|
+
*
|
|
33
|
+
* Performs case-insensitive checks against the source HTML and only
|
|
34
|
+
* injects elements that are not already present. The injection order
|
|
35
|
+
* is: doctype, charset, viewport, CSS reset, error boundary.
|
|
36
|
+
*
|
|
37
|
+
* @param html - Raw HTML content to wrap.
|
|
38
|
+
* @returns The wrapped HTML with all missing defaults injected.
|
|
39
|
+
*/
|
|
40
|
+
wrap(html) {
|
|
41
|
+
const lower = html.toLowerCase();
|
|
42
|
+
let result = html;
|
|
43
|
+
// 1. Add <!DOCTYPE html> if missing
|
|
44
|
+
if (!lower.includes('<!doctype html>')) {
|
|
45
|
+
result = '<!DOCTYPE html>\n' + result;
|
|
46
|
+
}
|
|
47
|
+
// 2. Add <meta charset="utf-8"> if missing
|
|
48
|
+
if (!lower.includes('charset')) {
|
|
49
|
+
result = this.injectIntoHead(result, '<meta charset="utf-8">');
|
|
50
|
+
}
|
|
51
|
+
// 3. Add viewport meta if missing
|
|
52
|
+
if (!lower.includes('viewport')) {
|
|
53
|
+
result = this.injectIntoHead(result, '<meta name="viewport" content="width=device-width, initial-scale=1">');
|
|
54
|
+
}
|
|
55
|
+
// 4. Prepend CSS reset
|
|
56
|
+
if (!lower.includes('box-sizing: border-box')) {
|
|
57
|
+
const resetCss = '<style>* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, sans-serif; }</style>';
|
|
58
|
+
result = this.injectIntoHead(result, resetCss);
|
|
59
|
+
}
|
|
60
|
+
// 5. Append error boundary script
|
|
61
|
+
if (!lower.includes('window.onerror')) {
|
|
62
|
+
const errorScript = `<script>
|
|
63
|
+
window.onerror = function(msg, url, line) {
|
|
64
|
+
var el = document.createElement('div');
|
|
65
|
+
el.style.cssText = 'position:fixed;top:0;left:0;right:0;padding:16px;background:#fee2e2;color:#991b1b;font:14px system-ui;z-index:99999';
|
|
66
|
+
el.textContent = 'Widget error: ' + msg + ' (line ' + line + ')';
|
|
67
|
+
document.body.prepend(el);
|
|
68
|
+
};
|
|
69
|
+
</script>`;
|
|
70
|
+
result = this.injectBeforeBodyClose(result, errorScript);
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Inject content into the `<head>` section of the HTML document.
|
|
76
|
+
*
|
|
77
|
+
* If a `<head>` tag exists, the content is inserted right after it.
|
|
78
|
+
* Otherwise, it is prepended to the document (after the doctype, if
|
|
79
|
+
* present).
|
|
80
|
+
*
|
|
81
|
+
* @param html - The HTML document string.
|
|
82
|
+
* @param content - The HTML fragment to inject.
|
|
83
|
+
* @returns The modified HTML with the content injected.
|
|
84
|
+
*/
|
|
85
|
+
injectIntoHead(html, content) {
|
|
86
|
+
const headIndex = html.toLowerCase().indexOf('<head>');
|
|
87
|
+
if (headIndex !== -1) {
|
|
88
|
+
const insertPos = headIndex + '<head>'.length;
|
|
89
|
+
return html.slice(0, insertPos) + '\n' + content + html.slice(insertPos);
|
|
90
|
+
}
|
|
91
|
+
// No <head> tag — insert after doctype if present, otherwise at the top
|
|
92
|
+
const doctypeEnd = html.toLowerCase().indexOf('<!doctype html>');
|
|
93
|
+
if (doctypeEnd !== -1) {
|
|
94
|
+
const insertPos = doctypeEnd + '<!doctype html>'.length;
|
|
95
|
+
return html.slice(0, insertPos) + '\n' + content + html.slice(insertPos);
|
|
96
|
+
}
|
|
97
|
+
return content + '\n' + html;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Inject content just before the closing `</body>` tag.
|
|
101
|
+
*
|
|
102
|
+
* If no `</body>` tag exists, the content is appended at the end
|
|
103
|
+
* of the document.
|
|
104
|
+
*
|
|
105
|
+
* @param html - The HTML document string.
|
|
106
|
+
* @param content - The HTML fragment to inject.
|
|
107
|
+
* @returns The modified HTML with the content injected.
|
|
108
|
+
*/
|
|
109
|
+
injectBeforeBodyClose(html, content) {
|
|
110
|
+
const bodyCloseIndex = html.toLowerCase().indexOf('</body>');
|
|
111
|
+
if (bodyCloseIndex !== -1) {
|
|
112
|
+
return html.slice(0, bodyCloseIndex) + content + '\n' + html.slice(bodyCloseIndex);
|
|
113
|
+
}
|
|
114
|
+
return html + '\n' + content;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=WidgetWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetWrapper.js","sourceRoot":"","sources":["../src/WidgetWrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,aAAa;IACxB;;;;;;;;;OASG;IACH,IAAI,CAAC,IAAY;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,MAAM,GAAG,IAAI,CAAC;QAElB,oCAAoC;QACpC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACvC,MAAM,GAAG,mBAAmB,GAAG,MAAM,CAAC;QACxC,CAAC;QAED,2CAA2C;QAC3C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QACjE,CAAC;QAED,kCAAkC;QAClC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,IAAI,CAAC,cAAc,CAC1B,MAAM,EACN,sEAAsE,CACvE,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;YAC9C,MAAM,QAAQ,GACZ,kHAAkH,CAAC;YACrH,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAED,kCAAkC;QAClC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtC,MAAM,WAAW,GAAG;;;;;;;UAOhB,CAAC;YACL,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;OAUG;IACK,cAAc,CAAC,IAAY,EAAE,OAAe;QAClD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEvD,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC3E,CAAC;QAED,wEAAwE;QACxE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACjE,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC;YACxD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;IAC/B,CAAC;IAED;;;;;;;;;OASG;IACK,qBAAqB,CAAC,IAAY,EAAE,OAAe;QACzD,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE7D,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACrF,CAAC;QAED,OAAO,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC;IAC/B,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module index
|
|
3
|
+
*
|
|
4
|
+
* Widget Generator Extension Pack — generates self-contained interactive
|
|
5
|
+
* HTML/CSS/JS widgets with safety wrapping and file management.
|
|
6
|
+
*
|
|
7
|
+
* Entry point for the extension; follows the standard AgentOS extension
|
|
8
|
+
* pack factory pattern (see {@link createExtensionPack}). The factory
|
|
9
|
+
* wires up the {@link WidgetWrapper} for HTML safety, the
|
|
10
|
+
* {@link WidgetFileManager} for file persistence, and registers the
|
|
11
|
+
* `generate_widget` tool.
|
|
12
|
+
*/
|
|
13
|
+
import { GenerateWidgetTool } from './tools/generateWidget.js';
|
|
14
|
+
/**
|
|
15
|
+
* Options accepted by the Widget Generator extension pack factory.
|
|
16
|
+
*/
|
|
17
|
+
export interface WidgetGeneratorExtensionOptions {
|
|
18
|
+
/** Override the default priority used when registering the tool. */
|
|
19
|
+
priority?: number;
|
|
20
|
+
/** Override the agent workspace directory (defaults to `process.cwd()`). */
|
|
21
|
+
workspaceDir?: string;
|
|
22
|
+
/** Override the server port used for widget URLs (defaults to `3777`). */
|
|
23
|
+
serverPort?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Factory function called by the AgentOS extension loader. Returns a pack
|
|
27
|
+
* descriptor containing the `generate_widget` tool.
|
|
28
|
+
*
|
|
29
|
+
* The factory:
|
|
30
|
+
*
|
|
31
|
+
* 1. Resolves the workspace directory and server port from context options.
|
|
32
|
+
* 2. Creates the {@link WidgetWrapper} for HTML safety wrapping.
|
|
33
|
+
* 3. Creates the {@link WidgetFileManager} for file I/O.
|
|
34
|
+
* 4. Wires both into the {@link GenerateWidgetTool}.
|
|
35
|
+
* 5. Returns the tool as an extension pack descriptor with lifecycle hooks.
|
|
36
|
+
*
|
|
37
|
+
* @param context - Extension activation context provided by the AgentOS runtime.
|
|
38
|
+
* @returns An extension pack with tool descriptors and lifecycle hooks.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createExtensionPack(context: any): {
|
|
41
|
+
name: string;
|
|
42
|
+
version: string;
|
|
43
|
+
descriptors: {
|
|
44
|
+
id: string;
|
|
45
|
+
kind: "tool";
|
|
46
|
+
priority: number;
|
|
47
|
+
payload: GenerateWidgetTool;
|
|
48
|
+
}[];
|
|
49
|
+
onActivate: () => Promise<any>;
|
|
50
|
+
onDeactivate: () => Promise<any>;
|
|
51
|
+
};
|
|
52
|
+
export default createExtensionPack;
|
|
53
|
+
export { WidgetWrapper } from './WidgetWrapper.js';
|
|
54
|
+
export { WidgetFileManager } from './WidgetFileManager.js';
|
|
55
|
+
export { GenerateWidgetTool } from './tools/generateWidget.js';
|
|
56
|
+
export type { GenerateWidgetInput, GenerateWidgetOutput } from './types.js';
|
|
57
|
+
export type { WidgetFileEntry, WidgetSaveResult } from './WidgetFileManager.js';
|
|
58
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG;;;;;;;;;;;EAiC/C;AAED,eAAe,mBAAmB,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAG/D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module index
|
|
3
|
+
*
|
|
4
|
+
* Widget Generator Extension Pack — generates self-contained interactive
|
|
5
|
+
* HTML/CSS/JS widgets with safety wrapping and file management.
|
|
6
|
+
*
|
|
7
|
+
* Entry point for the extension; follows the standard AgentOS extension
|
|
8
|
+
* pack factory pattern (see {@link createExtensionPack}). The factory
|
|
9
|
+
* wires up the {@link WidgetWrapper} for HTML safety, the
|
|
10
|
+
* {@link WidgetFileManager} for file persistence, and registers the
|
|
11
|
+
* `generate_widget` tool.
|
|
12
|
+
*/
|
|
13
|
+
import { WidgetWrapper } from './WidgetWrapper.js';
|
|
14
|
+
import { WidgetFileManager } from './WidgetFileManager.js';
|
|
15
|
+
import { GenerateWidgetTool } from './tools/generateWidget.js';
|
|
16
|
+
/**
|
|
17
|
+
* Factory function called by the AgentOS extension loader. Returns a pack
|
|
18
|
+
* descriptor containing the `generate_widget` tool.
|
|
19
|
+
*
|
|
20
|
+
* The factory:
|
|
21
|
+
*
|
|
22
|
+
* 1. Resolves the workspace directory and server port from context options.
|
|
23
|
+
* 2. Creates the {@link WidgetWrapper} for HTML safety wrapping.
|
|
24
|
+
* 3. Creates the {@link WidgetFileManager} for file I/O.
|
|
25
|
+
* 4. Wires both into the {@link GenerateWidgetTool}.
|
|
26
|
+
* 5. Returns the tool as an extension pack descriptor with lifecycle hooks.
|
|
27
|
+
*
|
|
28
|
+
* @param context - Extension activation context provided by the AgentOS runtime.
|
|
29
|
+
* @returns An extension pack with tool descriptors and lifecycle hooks.
|
|
30
|
+
*/
|
|
31
|
+
export function createExtensionPack(context) {
|
|
32
|
+
const options = (context.options || {});
|
|
33
|
+
// Resolve configuration
|
|
34
|
+
const workspaceDir = options.workspaceDir ?? process.cwd();
|
|
35
|
+
const serverPort = options.serverPort ?? 3777;
|
|
36
|
+
const priority = options.priority ?? 50;
|
|
37
|
+
// Create dependencies
|
|
38
|
+
const wrapper = new WidgetWrapper();
|
|
39
|
+
const fileManager = new WidgetFileManager(workspaceDir, serverPort);
|
|
40
|
+
// Create the tool with all dependencies injected
|
|
41
|
+
const tool = new GenerateWidgetTool(wrapper, fileManager);
|
|
42
|
+
return {
|
|
43
|
+
name: '@framers/agentos-ext-widget-generator',
|
|
44
|
+
version: '1.0.0',
|
|
45
|
+
descriptors: [
|
|
46
|
+
{
|
|
47
|
+
// IMPORTANT: ToolExecutor uses descriptor id as the lookup key for tool calls.
|
|
48
|
+
// Keep it aligned with `tool.name`.
|
|
49
|
+
id: tool.name,
|
|
50
|
+
kind: 'tool',
|
|
51
|
+
priority,
|
|
52
|
+
payload: tool,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
onActivate: async () => context.logger?.info('Interactive Widgets activated'),
|
|
56
|
+
onDeactivate: async () => context.logger?.info('Interactive Widgets deactivated'),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export default createExtensionPack;
|
|
60
|
+
// Re-export classes for direct consumption
|
|
61
|
+
export { WidgetWrapper } from './WidgetWrapper.js';
|
|
62
|
+
export { WidgetFileManager } from './WidgetFileManager.js';
|
|
63
|
+
export { GenerateWidgetTool } from './tools/generateWidget.js';
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAgB/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAY;IAC9C,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAoC,CAAC;IAE3E,wBAAwB;IACxB,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IAExC,sBAAsB;IACtB,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,IAAI,iBAAiB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAEpE,iDAAiD;IACjD,MAAM,IAAI,GAAG,IAAI,kBAAkB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAE1D,OAAO;QACL,IAAI,EAAE,uCAAuC;QAC7C,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE;YACX;gBACE,+EAA+E;gBAC/E,oCAAoC;gBACpC,EAAE,EAAE,IAAI,CAAC,IAAI;gBACb,IAAI,EAAE,MAAe;gBACrB,QAAQ;gBACR,OAAO,EAAE,IAAI;aACd;SACF;QACD,UAAU,EAAE,KAAK,IAAI,EAAE,CACrB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,+BAA+B,CAAC;QACvD,YAAY,EAAE,KAAK,IAAI,EAAE,CACvB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,iCAAiC,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,eAAe,mBAAmB,CAAC;AAEnC,2CAA2C;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|