@mieweb/q 1.0.0 → 1.2.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/README.md CHANGED
@@ -1,932 +1,932 @@
1
- # Q — Agent Config Generator
2
-
3
- **Q** is a powerful, embeddable UI component for generating and editing AI Agent configuration files. It provides a form-based interface, a YAML/JSON code editor, and an MCP tool builder — all in one package. Built with React and [@mieweb/ui](https://www.npmjs.com/package/@mieweb/ui), Q can be dropped into any React application or used framework-agnostically in Vanilla JS, Vue, Angular, Svelte, or any other environment.
4
-
5
- ## Table of Contents
6
-
7
- - [Features](#features)
8
- - [Prerequisites](#prerequisites)
9
- - [Installation](#installation)
10
- - [Quick Start — React](#quick-start--react)
11
- - [Quick Start — Universal (Vanilla JS / Any Framework)](#quick-start--universal-vanilla-js--any-framework)
12
- - [API Reference](#api-reference)
13
- - [React — `AgentConfigGenerator`](#react--agentconfiggenerator)
14
- - [Universal — `UniversalAgentConfigGenerator`](#universal--universalagentconfiggenerator)
15
- - [Exported Utilities](#exported-utilities)
16
- - [Styling & CSS](#styling--css)
17
- - [Theming & Brand Customization](#theming--brand-customization)
18
- - [Custom Schemas](#custom-schemas)
19
- - [Architecture & Flow Diagram](#architecture--flow-diagram)
20
- - [Project Structure](#project-structure)
21
- - [Development](#development)
22
- - [Troubleshooting](#troubleshooting)
23
- - [License](#license)
24
-
25
- ---
26
-
27
- ## Features
28
-
29
- - **Form Builder** — Auto-generated form UI from a customizable JSON schema. Add, remove, and reorder fields visually with a built-in schema editor.
30
- - **Config Editor** — Full-featured YAML/JSON editor powered by Monaco (the engine behind VS Code). Edit configs directly with syntax highlighting and validation.
31
- - **Tool Builder** — Visual builder for defining MCP (Model Context Protocol) tools with parameter schemas, following the open standard.
32
- - **Bidirectional Sync** — Changes in the form update the code editor and vice versa, always keeping the config in sync.
33
- - **Download & Submit** — Download the generated config as YAML or JSON, or submit it programmatically via callbacks.
34
- - **Schema Import/Export** — Import and export the form schema as JSON for portability and version control.
35
- - **Customizable Theming** — Powered by `@mieweb/ui` CSS variables. Supports multiple built-in brands (Bluehive, MIEWeb, Enterprise Health, Ozwell, Waggleline, WebChart) or fully custom themes.
36
- - **Framework Agnostic** — Use the React component directly or the Universal wrapper for any framework (Vue, Angular, Svelte, plain HTML).
37
-
38
- ---
39
-
40
- ## Prerequisites
41
-
42
- | Requirement | Version | Notes |
43
- | --------------- | ---------------- | ------------------------------------------------------------ |
44
- | **Node.js** | 18+ | LTS recommended. [Download here](https://nodejs.org/). Check with `node -v` |
45
- | **npm** | 9+ | Bundled with Node.js. Check with `npm -v` |
46
- | **Bundler** | Vite 5+, Webpack 5+, or similar | Any modern bundler that supports ES modules |
47
- | **React** _(React integration only)_ | 18+ or 19+ | The Universal wrapper includes React internally |
48
-
49
- ---
50
-
51
- ## Installation
52
-
53
- Install Q directly from GitHub:
54
-
55
- ```bash
56
- npm install Q@github:avagu-mie/Q
57
- ```
58
-
59
- This will:
60
- 1. Clone the repository
61
- 2. Run the `prepare` script (builds the library with Vite and compiles Tailwind CSS)
62
- 3. Install the generated `dist/` folder into your `node_modules/Q`
63
-
64
- > **Note:** Because Q is installed from source (not a pre-built npm package), the `prepare` step builds the library on your machine. This requires all of Q's dependencies to be fetched and may take a minute or two on the first install. Subsequent installs will be faster if your npm cache is warm.
65
-
66
- > **Tip:** Once published to npm, you can install with `npm install Q` instead.
67
-
68
- ---
69
-
70
- ## Quick Start — React
71
-
72
- This section walks through creating a brand-new React application that uses Q from scratch.
73
-
74
- ### 1. Scaffold the Application
75
-
76
- ```bash
77
- # Create a new project folder
78
- mkdir my-q-react-app && cd my-q-react-app
79
-
80
- # Initialize package.json
81
- npm init -y
82
-
83
- # Make sure package.json has "type": "module"
84
- ```
85
-
86
- Edit your `package.json` so it looks like this:
87
-
88
- ```json
89
- {
90
- "name": "my-q-react-app",
91
- "private": true,
92
- "version": "1.0.0",
93
- "type": "module",
94
- "scripts": {
95
- "dev": "vite",
96
- "build": "vite build",
97
- "preview": "vite preview"
98
- }
99
- }
100
- ```
101
-
102
- ### 2. Install Dependencies
103
-
104
- ```bash
105
- # Install Q from GitHub
106
- npm install Q@github:avagu-mie/Q
107
-
108
- # Install React (only if your app doesn't already have React)
109
- npm install react react-dom
110
-
111
- # Install Vite and the React plugin as dev dependencies
112
- npm install -D vite @vitejs/plugin-react
113
- ```
114
-
115
- > **Note:** Q includes `react` and `react-dom` as direct dependencies, so you don't need to install them separately. If your host app already has React installed, npm will deduplicate automatically. If you see "Invalid hook call" errors at runtime, ensure you only have **one copy** of React — run `npm ls react` to check. You can add a [resolution override](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides) if needed.
116
-
117
- ### 3. Create Project Files
118
-
119
- **`vite.config.js`**
120
- ```js
121
- import { defineConfig } from 'vite';
122
- import react from '@vitejs/plugin-react';
123
-
124
- export default defineConfig({
125
- plugins: [react()],
126
- });
127
- ```
128
-
129
- **`index.html`**
130
- ```html
131
- <!doctype html>
132
- <html lang="en">
133
- <head>
134
- <meta charset="UTF-8" />
135
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
136
- <title>My Q App</title>
137
- <style>
138
- * { box-sizing: border-box; margin: 0; padding: 0; }
139
- html, body, #root { height: 100%; }
140
- </style>
141
- </head>
142
- <body>
143
- <div id="root"></div>
144
- <script type="module" src="/src/main.jsx"></script>
145
- </body>
146
- </html>
147
- ```
148
-
149
- **`src/main.jsx`**
150
- ```jsx
151
- import React, { useState } from 'react';
152
- import ReactDOM from 'react-dom/client';
153
- import { AgentConfigGenerator } from 'Q';
154
- import 'Q/style.css'; // Required — loads all component styles
155
-
156
- function App() {
157
- const [submittedYaml, setSubmittedYaml] = useState('');
158
-
159
- return (
160
- <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
161
- <AgentConfigGenerator
162
- showEditor={true}
163
- onConfigChange={(config) => {
164
- console.log('Config changed:', config);
165
- }}
166
- onDownload={(content, mode) => {
167
- // content = serialized config string, mode = 'yaml' or 'json'
168
- console.log(`Download (${mode}):`, content);
169
- }}
170
- onSubmit={(yamlString) => {
171
- console.log('Submitted YAML:', yamlString);
172
- setSubmittedYaml(yamlString);
173
- }}
174
- />
175
-
176
- {submittedYaml && (
177
- <pre style={{
178
- margin: '1rem',
179
- padding: '1rem',
180
- background: '#f5f5f5',
181
- borderRadius: '8px',
182
- overflow: 'auto',
183
- maxHeight: '300px',
184
- fontSize: '0.85rem',
185
- }}>
186
- {submittedYaml}
187
- </pre>
188
- )}
189
- </div>
190
- );
191
- }
192
-
193
- ReactDOM.createRoot(document.getElementById('root')).render(<App />);
194
- ```
195
-
196
- ### 4. Run the Application
197
-
198
- ```bash
199
- npm run dev
200
- ```
201
-
202
- Open the URL shown in your terminal (usually `http://localhost:5173`).
203
-
204
- ---
205
-
206
- ## Quick Start — Universal (Vanilla JS / Any Framework)
207
-
208
- The Universal wrapper lets you use Q **without writing any React code**. It works with plain HTML, Vue, Angular, Svelte, or any framework. React is bundled internally.
209
-
210
- ### 1. Scaffold the Application
211
-
212
- ```bash
213
- mkdir my-q-universal-app && cd my-q-universal-app
214
- npm init -y
215
- ```
216
-
217
- Edit your `package.json`:
218
-
219
- ```json
220
- {
221
- "name": "my-q-universal-app",
222
- "private": true,
223
- "version": "1.0.0",
224
- "type": "module",
225
- "scripts": {
226
- "dev": "vite",
227
- "build": "vite build",
228
- "preview": "vite preview"
229
- }
230
- }
231
- ```
232
-
233
- ### 2. Install Dependencies
234
-
235
- ```bash
236
- # Install Q from GitHub (React is included as a dependency of Q)
237
- npm install Q@github:avagu-mie/Q
238
-
239
- # Install Vite as a dev dependency — no React plugin needed!
240
- npm install -D vite
241
- ```
242
-
243
- ### 3. Create Project Files
244
-
245
- **`vite.config.js`**
246
- ```js
247
- import { defineConfig } from 'vite';
248
-
249
- export default defineConfig({});
250
- ```
251
-
252
- **`index.html`**
253
- ```html
254
- <!doctype html>
255
- <html lang="en">
256
- <head>
257
- <meta charset="UTF-8" />
258
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
259
- <title>My Q App</title>
260
- <style>
261
- * { box-sizing: border-box; margin: 0; padding: 0; }
262
- html, body { height: 100%; }
263
- #config-container { height: 100%; }
264
- </style>
265
- </head>
266
- <body>
267
- <div id="config-container"></div>
268
- <script type="module" src="/src/main.js"></script>
269
- </body>
270
- </html>
271
- ```
272
-
273
- **`src/main.js`**
274
- ```js
275
- import { UniversalAgentConfigGenerator } from 'Q/universal';
276
- import 'Q/style.css'; // Required — loads all component styles
277
-
278
- // Mount Q into the container element
279
- const generator = new UniversalAgentConfigGenerator('#config-container', {
280
- showEditor: true,
281
- });
282
-
283
- const container = document.getElementById('config-container');
284
-
285
- // Listen for config changes
286
- container.addEventListener('config-change', (e) => {
287
- console.log('Config changed:', e.detail);
288
- });
289
-
290
- // Listen for download requests
291
- container.addEventListener('config-download', (e) => {
292
- console.log('Download requested:', e.detail);
293
- });
294
-
295
- // Listen for submit
296
- container.addEventListener('config-submit', (e) => {
297
- console.log('Submit clicked:', e.detail);
298
- // e.detail.yaml — the config as a YAML string
299
- // e.detail.config — the config as a JS object
300
- });
301
- ```
302
-
303
- ### 4. Run the Application
304
-
305
- ```bash
306
- npm run dev
307
- ```
308
-
309
- ### Universal Wrapper in Vue
310
-
311
- ```vue
312
- <template>
313
- <div ref="container" style="height: 100%"></div>
314
- </template>
315
-
316
- <script>
317
- import { UniversalAgentConfigGenerator } from 'Q/universal';
318
- import 'Q/style.css';
319
-
320
- export default {
321
- mounted() {
322
- this.generator = new UniversalAgentConfigGenerator(this.$refs.container, {
323
- showEditor: true,
324
- });
325
-
326
- this.$refs.container.addEventListener('config-submit', (e) => {
327
- this.$emit('submit', e.detail);
328
- });
329
- },
330
- beforeUnmount() {
331
- this.generator.destroy();
332
- },
333
- };
334
- </script>
335
- ```
336
-
337
- ### Universal Wrapper in Angular
338
-
339
- ```typescript
340
- import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
341
- import { UniversalAgentConfigGenerator } from 'Q/universal';
342
- import 'Q/style.css';
343
-
344
- @Component({
345
- selector: 'app-config-generator',
346
- template: `<div #container style="height: 100%"></div>`,
347
- })
348
- export class ConfigGeneratorComponent implements AfterViewInit, OnDestroy {
349
- @ViewChild('container') container!: ElementRef;
350
- private generator!: UniversalAgentConfigGenerator;
351
-
352
- ngAfterViewInit() {
353
- this.generator = new UniversalAgentConfigGenerator(this.container.nativeElement, {
354
- showEditor: true,
355
- });
356
-
357
- this.container.nativeElement.addEventListener('config-submit', (e: CustomEvent) => {
358
- console.log('Submitted:', e.detail);
359
- });
360
- }
361
-
362
- ngOnDestroy() {
363
- this.generator.destroy();
364
- }
365
- }
366
- ```
367
-
368
- ---
369
-
370
- ## API Reference
371
-
372
- ### React — `AgentConfigGenerator`
373
-
374
- ```jsx
375
- import { AgentConfigGenerator } from 'Q';
376
- ```
377
-
378
- | Prop | Type | Default | Description |
379
- | ---------------- | ------------------------------ | ---------------- | --------------------------------------------------------------------------- |
380
- | `initialConfig` | `object` | auto-derived | Pre-populate with an existing agent config object |
381
- | `schema` | `object` | built-in schema | Override the default questionnaire schema (MieForms v1.0 format) |
382
- | `onConfigChange` | `(config: object) => void` | — | Callback fired on every config change |
383
- | `onDownload` | `(content: string, mode: 'yaml' \| 'json') => void` | — | Callback when the user clicks Download. Receives the serialized config and the format. |
384
- | `onSubmit` | `(yamlString: string) => void` | — | Callback when the user clicks Submit. Receives the config as a YAML string. Also shows the Submit button. |
385
- | `showEditor` | `boolean` | `true` | Show/hide the Config Editor tab |
386
-
387
- ### Universal — `UniversalAgentConfigGenerator`
388
-
389
- ```js
390
- import { UniversalAgentConfigGenerator } from 'Q/universal';
391
- ```
392
-
393
- #### Constructor
394
-
395
- ```js
396
- new UniversalAgentConfigGenerator(target, options?)
397
- ```
398
-
399
- | Parameter | Type | Description |
400
- | ------------------ | ----------------------- | ----------------------------------------------------------- |
401
- | `target` | `string \| HTMLElement` | CSS selector or DOM element to mount into |
402
- | `options.initialConfig` | `object` | Pre-populate with an existing agent config |
403
- | `options.schema` | `object` | Override the default questionnaire schema |
404
- | `options.showEditor` | `boolean` | Show the Config Editor tab (default: `true`) |
405
-
406
- #### Methods
407
-
408
- | Method | Description |
409
- | ------------------- | ---------------------------------------- |
410
- | `update(options)` | Merge new options and re-render |
411
- | `destroy()` | Unmount the component and free resources |
412
-
413
- #### DOM Events
414
-
415
- Events are dispatched on the container element. Use `addEventListener` to listen:
416
-
417
- | Event Name | `e.detail` | Description |
418
- | ----------------- | -------------------------------------- | ------------------------------------------------ |
419
- | `config-change` | `object` (the config) | Fired on every config change |
420
- | `config-download` | `{ content: string, mode: 'yaml' \| 'json' }` | Fired when the user clicks Download |
421
- | `config-submit` | `{ config: object, yaml: string }` | Fired when the user clicks Submit |
422
-
423
- ---
424
-
425
- ## Exported Utilities
426
-
427
- In addition to the main components, Q exports several utilities:
428
-
429
- ```js
430
- import {
431
- // Components
432
- AgentConfigGenerator,
433
- FormBuilder,
434
- ConfigEditor,
435
- ToolBuilder,
436
- Header,
437
-
438
- // Schema / Config helpers
439
- defaultSchema, // The built-in questionnaire JSON schema
440
- deriveDefaultConfig, // (schema) => config object with defaults
441
- questionnaireToConfig, // Convert schema answers to a config object
442
- configToQuestionnaire, // Sync a config object back into a schema
443
- validateConfig, // Validate a config object
444
- configToYaml, // Convert config to YAML string
445
- yamlToConfig, // Parse YAML string to config object
446
- downloadConfig, // Trigger a file download
447
- copyToClipboard, // Copy text to clipboard
448
-
449
- // Constants
450
- TIMEZONES, // Array of timezone strings
451
- GENERIC_TOOLS, // Built-in MCP tool definitions
452
- } from 'Q';
453
- ```
454
-
455
- The Universal entry also re-exports branding helpers:
456
-
457
- ```js
458
- import { brands, generateBrandCSS } from 'Q/universal';
459
- ```
460
-
461
- ---
462
-
463
- ## Styling & CSS
464
-
465
- Q uses [Tailwind CSS](https://tailwindcss.com/) internally and ships a pre-built CSS file. **You must import the stylesheet** in your application for components to render correctly:
466
-
467
- ```js
468
- import 'Q/style.css';
469
- ```
470
-
471
- This single import includes:
472
- - All Tailwind utility classes used by Q components
473
- - All `@mieweb/ui` component styles
474
- - Custom animations and hover-state overrides
475
-
476
- ### Full-Height Layout
477
-
478
- Q is designed to fill its parent container. Make sure the mount target has a defined height:
479
-
480
- ```css
481
- html, body, #root { height: 100%; }
482
- ```
483
-
484
- ### Using Q alongside your own Tailwind setup
485
-
486
- If your host app also uses Tailwind, you can extend your own config with Q's preset:
487
-
488
- ```js
489
- // your-app/tailwind.config.js
490
- import miewebPreset from 'Q/tailwind-config';
491
-
492
- export default {
493
- presets: [miewebPreset],
494
- content: [
495
- './src/**/*.{js,jsx,ts,tsx}',
496
- './node_modules/Q/dist/**/*.{js,cjs}', // Scan Q's built output
497
- ],
498
- };
499
- ```
500
-
501
- ---
502
-
503
- ## Theming & Brand Customization
504
-
505
- Q is styled entirely through **CSS custom properties** (variables) defined by `@mieweb/ui`. You can re-theme the entire component by setting these variables on a parent element.
506
-
507
- ### Built-in Brands
508
-
509
- `@mieweb/ui` ships with 6 built-in brand themes. Import the desired brand CSS **before** Q's styles:
510
-
511
- | Brand | Import |
512
- | ------------------ | ------------------------------------------ |
513
- | Bluehive (default) | `@mieweb/ui/brands/bluehive.css` |
514
- | Enterprise Health | `@mieweb/ui/brands/enterprise-health.css` |
515
- | MIEWeb | `@mieweb/ui/brands/mieweb.css` |
516
- | Ozwell | `@mieweb/ui/brands/ozwell.css` |
517
- | WebChart | `@mieweb/ui/brands/webchart.css` |
518
- | Waggleline | `@mieweb/ui/brands/waggleline.css` |
519
-
520
- Example (React):
521
-
522
- ```jsx
523
- import '@mieweb/ui/brands/enterprise-health.css';
524
- import 'Q/style.css';
525
- import { AgentConfigGenerator } from 'Q';
526
- ```
527
-
528
- ### Custom Theme via CSS Variables
529
-
530
- Create your own theme by setting the CSS variables on a parent element or `:root`:
531
-
532
- ```css
533
- :root {
534
- /* Colors */
535
- --mieweb-background: #ffffff;
536
- --mieweb-foreground: #0a0a0a;
537
- --mieweb-card: #ffffff;
538
- --mieweb-card-foreground: #0a0a0a;
539
- --mieweb-primary: #2563eb;
540
- --mieweb-primary-foreground: #ffffff;
541
- --mieweb-secondary: #f5f5f5;
542
- --mieweb-secondary-foreground: #171717;
543
- --mieweb-muted: #f5f5f5;
544
- --mieweb-muted-foreground: #737373;
545
- --mieweb-accent: #f5f5f5;
546
- --mieweb-accent-foreground: #171717;
547
- --mieweb-destructive: #ef4444;
548
- --mieweb-destructive-foreground: #ffffff;
549
- --mieweb-border: #e5e5e5;
550
- --mieweb-input: #e5e5e5;
551
- --mieweb-ring: #2563eb;
552
-
553
- /* Typography */
554
- --mieweb-font-sans: 'Inter', system-ui, sans-serif;
555
-
556
- /* Border Radius */
557
- --mieweb-radius-sm: 0.375rem;
558
- --mieweb-radius-md: 0.5rem;
559
- --mieweb-radius-lg: 0.75rem;
560
- }
561
- ```
562
-
563
- ### Scoped Theming
564
-
565
- Apply different themes to different instances on the same page by scoping CSS variables to a wrapper element:
566
-
567
- ```html
568
- <div class="theme-dark" style="
569
- --mieweb-background: #1a1a1a;
570
- --mieweb-foreground: #fafafa;
571
- --mieweb-card: #262626;
572
- --mieweb-border: #404040;
573
- ">
574
- <div id="config-container"></div>
575
- </div>
576
- ```
577
-
578
- ---
579
-
580
- ## Custom Schemas
581
-
582
- Q uses a JSON schema format (MieForms v1.0) to define the form fields. You can pass a custom schema to control which fields appear in the Form Builder.
583
-
584
- ### Schema Structure
585
-
586
- ```json
587
- {
588
- "schemaType": "mieforms-v1.0",
589
- "title": "My Custom Form",
590
- "fields": [
591
- {
592
- "id": "section-1",
593
- "fieldType": "section",
594
- "title": "General Settings",
595
- "fields": [
596
- {
597
- "id": "name",
598
- "fieldType": "text",
599
- "question": "Agent Name",
600
- "answer": "My Agent",
601
- "required": true
602
- },
603
- {
604
- "id": "provider",
605
- "fieldType": "dropdown",
606
- "question": "LLM Provider",
607
- "answer": "openai",
608
- "options": ["openai", "anthropic", "google"]
609
- },
610
- {
611
- "id": "enableLogging",
612
- "fieldType": "check",
613
- "question": "Enable Logging",
614
- "answer": false
615
- },
616
- {
617
- "id": "systemPrompt",
618
- "fieldType": "longtext",
619
- "question": "System Prompt",
620
- "answer": ""
621
- }
622
- ]
623
- }
624
- ]
625
- }
626
- ```
627
-
628
- ### Supported Field Types
629
-
630
- | Type | Description |
631
- | ---------- | ----------------------------------------------- |
632
- | `text` | Single-line text input |
633
- | `longtext` | Multi-line textarea |
634
- | `dropdown` | Select dropdown (requires `options` array) |
635
- | `check` | Boolean checkbox |
636
- | `section` | Grouping container (contains nested `fields`) |
637
-
638
- ### Using Nested Keys
639
-
640
- Use dot-notation in the field `id` to map to nested config keys:
641
-
642
- ```json
643
- {
644
- "id": "twilio.phoneNumber",
645
- "fieldType": "text",
646
- "question": "Twilio Phone Number"
647
- }
648
- ```
649
-
650
- This produces:
651
-
652
- ```yaml
653
- twilio:
654
- phoneNumber: "+1234567890"
655
- ```
656
-
657
- ### Passing a Custom Schema
658
-
659
- ```jsx
660
- import customSchema from './my-schema.json';
661
-
662
- <AgentConfigGenerator
663
- schema={customSchema}
664
- onSubmit={(yaml) => console.log(yaml)}
665
- />
666
- ```
667
-
668
- ---
669
-
670
- ## Architecture & Flow Diagram
671
-
672
- ```mermaid
673
- flowchart TB
674
- subgraph Host["Host Application"]
675
- direction TB
676
- R["React App"]
677
- U["Universal Wrapper<br/>(Vanilla JS / Vue / Angular)"]
678
- end
679
-
680
- subgraph Q["Q Package"]
681
- direction TB
682
-
683
- subgraph Entry["Entry Points"]
684
- RE["Q (React)<br/>import from 'Q'"]
685
- UE["Q/universal<br/>import from 'Q/universal'"]
686
- end
687
-
688
- subgraph Core["Core Components"]
689
- ACG["AgentConfigGenerator<br/>(orchestrator)"]
690
- FB["FormBuilder<br/>(questionnaire UI)"]
691
- CE["ConfigEditor<br/>(Monaco YAML/JSON)"]
692
- TB["ToolBuilder<br/>(MCP tool editor)"]
693
- end
694
-
695
- subgraph Data["Data Layer"]
696
- CFG["Config State<br/>(React useState)"]
697
- SCH["Schema State<br/>(MieForms v1.0)"]
698
- YAML["YAML/JSON<br/>Output Sync"]
699
- end
700
-
701
- subgraph Style["Styling"]
702
- CSS["Q/style.css<br/>(Tailwind bundle)"]
703
- VAR["CSS Variables<br/>(--mieweb-*)"]
704
- BRAND["Brand Themes<br/>(@mieweb/ui)"]
705
- end
706
- end
707
-
708
- R -->|"import { AgentConfigGenerator }"| RE
709
- U -->|"new UniversalAgentConfigGenerator()"| UE
710
- UE -->|"wraps with createRoot"| ACG
711
- RE --> ACG
712
-
713
- ACG --> FB
714
- ACG --> CE
715
- ACG --> TB
716
-
717
- FB -->|"form answers"| CFG
718
- CE -->|"editor changes"| CFG
719
- TB -->|"tool definitions"| CFG
720
- CFG -->|"sync"| YAML
721
- CFG <-->|"bidirectional"| SCH
722
-
723
- BRAND --> VAR
724
- VAR --> CSS
725
-
726
- ACG -->|"onConfigChange"| Host
727
- ACG -->|"onSubmit (YAML)"| Host
728
- ACG -->|"onDownload"| Host
729
- ```
730
-
731
- ### Data Flow
732
-
733
- ```mermaid
734
- sequenceDiagram
735
- participant User
736
- participant FormBuilder
737
- participant ConfigState
738
- participant ConfigEditor
739
- participant HostApp
740
-
741
- User->>FormBuilder: Fill out form fields
742
- FormBuilder->>ConfigState: Update config object
743
- ConfigState->>ConfigEditor: Sync YAML/JSON strings
744
- ConfigState->>HostApp: onConfigChange(config)
745
-
746
- User->>ConfigEditor: Edit YAML/JSON directly
747
- ConfigEditor->>ConfigState: Parse & update config
748
- ConfigState->>FormBuilder: Re-render with new values
749
-
750
- User->>HostApp: Click Submit
751
- HostApp->>ConfigState: Read yamlOutput
752
- ConfigState-->>HostApp: onSubmit(yamlString)
753
- ```
754
-
755
- ### Component Tabs
756
-
757
- ```mermaid
758
- stateDiagram-v2
759
- [*] --> FormBuilder
760
-
761
- FormBuilder --> ConfigEditor: Switch tab
762
- FormBuilder --> ToolBuilder: Switch tab
763
- ConfigEditor --> FormBuilder: Switch tab
764
- ConfigEditor --> ToolBuilder: Switch tab
765
- ToolBuilder --> FormBuilder: Switch tab
766
- ToolBuilder --> ConfigEditor: Switch tab
767
-
768
- FormBuilder --> SchemaEditor: Click "Customize Form"
769
- SchemaEditor --> FormBuilder: Click "Back to Form"
770
-
771
- state FormBuilder {
772
- [*] --> RenderForm
773
- RenderForm: Questionnaire UI
774
- }
775
-
776
- state ConfigEditor {
777
- [*] --> YAML
778
- YAML --> JSON: Toggle
779
- JSON --> YAML: Toggle
780
- }
781
-
782
- state ToolBuilder {
783
- [*] --> ToolList
784
- ToolList: MCP Tool Definitions
785
- }
786
- ```
787
-
788
- ---
789
-
790
- ## Project Structure
791
-
792
- ```
793
- Q/
794
- ├── dist/ # Built output (generated)
795
- │ ├── index.js / index.cjs # React component library
796
- │ ├── universal.js / .cjs # Framework-agnostic wrapper
797
- │ └── style.css # Pre-built Tailwind CSS
798
- ├── src/
799
- │ ├── index.js # React entry — public exports
800
- │ ├── universal.jsx # Universal wrapper class
801
- │ ├── index.css # Tailwind directives + custom styles
802
- │ ├── components/
803
- │ │ ├── AgentConfigGenerator.jsx # Main orchestrator component
804
- │ │ ├── FormBuilder.jsx # Questionnaire form renderer
805
- │ │ ├── ConfigEditor.jsx # Monaco-based YAML/JSON editor
806
- │ │ └── ToolBuilder.jsx # MCP tool definition editor
807
- │ ├── schemas/
808
- │ │ └── agent-config-questionnaire.json # Default form schema
809
- │ ├── constants/
810
- │ │ └── defaults.js # Timezones, generic tools
811
- │ └── utils/
812
- │ ├── configHelpers.js # YAML/JSON conversion, download, clipboard
813
- │ └── transformers.js # Schema ↔ config transformations
814
- ├── package.json
815
- ├── vite.config.js # Dev server config
816
- ├── vite.lib.config.js # Library build config
817
- ├── tailwind.config.js # Tailwind CSS config with @mieweb/ui preset
818
- ├── postcss.config.js # PostCSS config (Tailwind + Autoprefixer)
819
- └── .npmrc # npm config (legacy-peer-deps)
820
- ```
821
-
822
- ---
823
-
824
- ## Development
825
-
826
- ### Running the Dev Server
827
-
828
- ```bash
829
- # Clone the repo
830
- git clone https://github.com/avagu-mie/Q.git && cd Q
831
-
832
- # Install dependencies
833
- npm install
834
-
835
- # Start the dev server with both React and Universal demo pages
836
- npm run dev # Opens index.html (default demo)
837
- npm run dev:react # Opens the React-specific demo page
838
- npm run dev:universal # Opens the Universal demo page
839
- ```
840
-
841
- ### Building the Library
842
-
843
- ```bash
844
- # Build the distributable library files
845
- npm run build:lib
846
-
847
- # Full prepare (build + CSS) — runs automatically on npm install from GitHub
848
- npm run prepare
849
- ```
850
-
851
- ### Key Scripts
852
-
853
- | Script | Description |
854
- | ----------------- | ------------------------------------------------------------- |
855
- | `npm run dev` | Start Vite dev server with HMR |
856
- | `npm run build` | Production build of the demo app |
857
- | `npm run build:lib` | Build the library (`dist/index.js`, `dist/universal.js`) |
858
- | `npm run prepare` | Full library build + Tailwind CSS compilation |
859
- | `npm run storybook` | Start Storybook for component development |
860
-
861
- ---
862
-
863
- ## Troubleshooting
864
-
865
- ### `npm install` fails with peer dependency errors
866
-
867
- Q uses `legacy-peer-deps=true` in its `.npmrc` to handle peer dependency conflicts between Storybook (which expects React 18) and the library (which supports React 19). If you encounter peer dep issues in your host app, create an `.npmrc` in your project root:
868
-
869
- ```
870
- legacy-peer-deps=true
871
- ```
872
-
873
- ### Styles not loading / unstyled components
874
-
875
- Make sure you import the CSS file:
876
-
877
- ```js
878
- import 'Q/style.css';
879
- ```
880
-
881
- This import is **required**. Without it, components will render without any styling.
882
-
883
- ### Component doesn't fill the page
884
-
885
- Q renders to fill its parent container. Ensure the parent element has an explicit height:
886
-
887
- ```css
888
- html, body, #root { height: 100%; }
889
- ```
890
-
891
- ### Monaco Editor not loading
892
-
893
- The Monaco editor (used in the Config Editor tab) is loaded asynchronously. Ensure your bundler supports dynamic imports (all modern bundlers do). If using a CSP (Content Security Policy), make sure `worker-src` allows blob URLs.
894
-
895
- ### Build errors with `ERR_PACKAGE_PATH_NOT_EXPORTED`
896
-
897
- If you see export map errors, check that you're importing from the correct path:
898
-
899
- ```js
900
- // ✅ Correct
901
- import { AgentConfigGenerator } from 'Q';
902
- import { UniversalAgentConfigGenerator } from 'Q/universal';
903
- import 'Q/style.css';
904
-
905
- // ❌ Wrong — don't import from dist/ directly
906
- import { AgentConfigGenerator } from 'Q/dist/index.js';
907
- ```
908
-
909
- ---
910
-
911
- ## Sample Output
912
-
913
- Here's an example of the YAML config that Q generates with the default schema:
914
-
915
- ```yaml
916
- _id: ""
917
- name: New Agent Config
918
- timezone: America/New_York
919
- description: Agent Assistant Description
920
- twilio:
921
- phoneNumber: ""
922
- accountSid: ""
923
- authToken: ""
924
- officeOpeningTime: 8
925
- officeClosingTime: 17
926
- systemPrompt: ""
927
- tools: []
928
- ```
929
-
930
- Each field in the form maps directly to a key in this output. Nested keys (like `twilio.phoneNumber`) are expanded into nested YAML objects. The Tool Builder tab adds entries to the `tools` array using the MCP `inputSchema` format.
931
-
932
-
1
+ # Q — Agent Config Generator
2
+
3
+ **Q** is a powerful, embeddable UI component for generating and editing AI Agent configuration files. It provides a form-based interface, a YAML/JSON code editor, and an MCP tool builder — all in one package. Built with React and [@mieweb/ui](https://www.npmjs.com/package/@mieweb/ui), Q can be dropped into any React application or used framework-agnostically in Vanilla JS, Vue, Angular, Svelte, or any other environment.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [Prerequisites](#prerequisites)
9
+ - [Installation](#installation)
10
+ - [Quick Start — React](#quick-start--react)
11
+ - [Quick Start — Universal (Vanilla JS / Any Framework)](#quick-start--universal-vanilla-js--any-framework)
12
+ - [API Reference](#api-reference)
13
+ - [React — `AgentConfigGenerator`](#react--agentconfiggenerator)
14
+ - [Universal — `UniversalAgentConfigGenerator`](#universal--universalagentconfiggenerator)
15
+ - [Exported Utilities](#exported-utilities)
16
+ - [Styling & CSS](#styling--css)
17
+ - [Theming & Brand Customization](#theming--brand-customization)
18
+ - [Custom Schemas](#custom-schemas)
19
+ - [Architecture & Flow Diagram](#architecture--flow-diagram)
20
+ - [Project Structure](#project-structure)
21
+ - [Development](#development)
22
+ - [Troubleshooting](#troubleshooting)
23
+ - [License](#license)
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ - **Form Builder** — Auto-generated form UI from a customizable JSON schema. Add, remove, and reorder fields visually with a built-in schema editor.
30
+ - **Config Editor** — Full-featured YAML/JSON editor powered by Monaco (the engine behind VS Code). Edit configs directly with syntax highlighting and validation.
31
+ - **Tool Builder** — Visual builder for defining MCP (Model Context Protocol) tools with parameter schemas, following the open standard.
32
+ - **Bidirectional Sync** — Changes in the form update the code editor and vice versa, always keeping the config in sync.
33
+ - **Download & Submit** — Download the generated config as YAML or JSON, or submit it programmatically via callbacks.
34
+ - **Schema Import/Export** — Import and export the form schema as JSON for portability and version control.
35
+ - **Customizable Theming** — Powered by `@mieweb/ui` CSS variables. Supports multiple built-in brands (Bluehive, MIEWeb, Enterprise Health, Ozwell, Waggleline, WebChart) or fully custom themes.
36
+ - **Framework Agnostic** — Use the React component directly or the Universal wrapper for any framework (Vue, Angular, Svelte, plain HTML).
37
+
38
+ ---
39
+
40
+ ## Prerequisites
41
+
42
+ | Requirement | Version | Notes |
43
+ | --------------- | ---------------- | ------------------------------------------------------------ |
44
+ | **Node.js** | 18+ | LTS recommended. [Download here](https://nodejs.org/). Check with `node -v` |
45
+ | **npm** | 9+ | Bundled with Node.js. Check with `npm -v` |
46
+ | **Bundler** | Vite 5+, Webpack 5+, or similar | Any modern bundler that supports ES modules |
47
+ | **React** _(React integration only)_ | 18+ or 19+ | The Universal wrapper includes React internally |
48
+
49
+ ---
50
+
51
+ ## Installation
52
+
53
+ Install Q directly from GitHub:
54
+
55
+ ```bash
56
+ npm install Q@github:avagu-mie/Q
57
+ ```
58
+
59
+ This will:
60
+ 1. Clone the repository
61
+ 2. Run the `prepare` script (builds the library with Vite and compiles Tailwind CSS)
62
+ 3. Install the generated `dist/` folder into your `node_modules/Q`
63
+
64
+ > **Note:** Because Q is installed from source (not a pre-built npm package), the `prepare` step builds the library on your machine. This requires all of Q's dependencies to be fetched and may take a minute or two on the first install. Subsequent installs will be faster if your npm cache is warm.
65
+
66
+ > **Tip:** Once published to npm, you can install with `npm install Q` instead.
67
+
68
+ ---
69
+
70
+ ## Quick Start — React
71
+
72
+ This section walks through creating a brand-new React application that uses Q from scratch.
73
+
74
+ ### 1. Scaffold the Application
75
+
76
+ ```bash
77
+ # Create a new project folder
78
+ mkdir my-q-react-app && cd my-q-react-app
79
+
80
+ # Initialize package.json
81
+ npm init -y
82
+
83
+ # Make sure package.json has "type": "module"
84
+ ```
85
+
86
+ Edit your `package.json` so it looks like this:
87
+
88
+ ```json
89
+ {
90
+ "name": "my-q-react-app",
91
+ "private": true,
92
+ "version": "1.0.0",
93
+ "type": "module",
94
+ "scripts": {
95
+ "dev": "vite",
96
+ "build": "vite build",
97
+ "preview": "vite preview"
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### 2. Install Dependencies
103
+
104
+ ```bash
105
+ # Install Q from GitHub
106
+ npm install Q@github:avagu-mie/Q
107
+
108
+ # Install React (only if your app doesn't already have React)
109
+ npm install react react-dom
110
+
111
+ # Install Vite and the React plugin as dev dependencies
112
+ npm install -D vite @vitejs/plugin-react
113
+ ```
114
+
115
+ > **Note:** Q includes `react` and `react-dom` as direct dependencies, so you don't need to install them separately. If your host app already has React installed, npm will deduplicate automatically. If you see "Invalid hook call" errors at runtime, ensure you only have **one copy** of React — run `npm ls react` to check. You can add a [resolution override](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides) if needed.
116
+
117
+ ### 3. Create Project Files
118
+
119
+ **`vite.config.js`**
120
+ ```js
121
+ import { defineConfig } from 'vite';
122
+ import react from '@vitejs/plugin-react';
123
+
124
+ export default defineConfig({
125
+ plugins: [react()],
126
+ });
127
+ ```
128
+
129
+ **`index.html`**
130
+ ```html
131
+ <!doctype html>
132
+ <html lang="en">
133
+ <head>
134
+ <meta charset="UTF-8" />
135
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
136
+ <title>My Q App</title>
137
+ <style>
138
+ * { box-sizing: border-box; margin: 0; padding: 0; }
139
+ html, body, #root { height: 100%; }
140
+ </style>
141
+ </head>
142
+ <body>
143
+ <div id="root"></div>
144
+ <script type="module" src="/src/main.jsx"></script>
145
+ </body>
146
+ </html>
147
+ ```
148
+
149
+ **`src/main.jsx`**
150
+ ```jsx
151
+ import React, { useState } from 'react';
152
+ import ReactDOM from 'react-dom/client';
153
+ import { AgentConfigGenerator } from 'Q';
154
+ import 'Q/style.css'; // Required — loads all component styles
155
+
156
+ function App() {
157
+ const [submittedYaml, setSubmittedYaml] = useState('');
158
+
159
+ return (
160
+ <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
161
+ <AgentConfigGenerator
162
+ showEditor={true}
163
+ onConfigChange={(config) => {
164
+ console.log('Config changed:', config);
165
+ }}
166
+ onDownload={(content, mode) => {
167
+ // content = serialized config string, mode = 'yaml' or 'json'
168
+ console.log(`Download (${mode}):`, content);
169
+ }}
170
+ onSubmit={(yamlString) => {
171
+ console.log('Submitted YAML:', yamlString);
172
+ setSubmittedYaml(yamlString);
173
+ }}
174
+ />
175
+
176
+ {submittedYaml && (
177
+ <pre style={{
178
+ margin: '1rem',
179
+ padding: '1rem',
180
+ background: '#f5f5f5',
181
+ borderRadius: '8px',
182
+ overflow: 'auto',
183
+ maxHeight: '300px',
184
+ fontSize: '0.85rem',
185
+ }}>
186
+ {submittedYaml}
187
+ </pre>
188
+ )}
189
+ </div>
190
+ );
191
+ }
192
+
193
+ ReactDOM.createRoot(document.getElementById('root')).render(<App />);
194
+ ```
195
+
196
+ ### 4. Run the Application
197
+
198
+ ```bash
199
+ npm run dev
200
+ ```
201
+
202
+ Open the URL shown in your terminal (usually `http://localhost:5173`).
203
+
204
+ ---
205
+
206
+ ## Quick Start — Universal (Vanilla JS / Any Framework)
207
+
208
+ The Universal wrapper lets you use Q **without writing any React code**. It works with plain HTML, Vue, Angular, Svelte, or any framework. React is bundled internally.
209
+
210
+ ### 1. Scaffold the Application
211
+
212
+ ```bash
213
+ mkdir my-q-universal-app && cd my-q-universal-app
214
+ npm init -y
215
+ ```
216
+
217
+ Edit your `package.json`:
218
+
219
+ ```json
220
+ {
221
+ "name": "my-q-universal-app",
222
+ "private": true,
223
+ "version": "1.0.0",
224
+ "type": "module",
225
+ "scripts": {
226
+ "dev": "vite",
227
+ "build": "vite build",
228
+ "preview": "vite preview"
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### 2. Install Dependencies
234
+
235
+ ```bash
236
+ # Install Q from GitHub (React is included as a dependency of Q)
237
+ npm install Q@github:avagu-mie/Q
238
+
239
+ # Install Vite as a dev dependency — no React plugin needed!
240
+ npm install -D vite
241
+ ```
242
+
243
+ ### 3. Create Project Files
244
+
245
+ **`vite.config.js`**
246
+ ```js
247
+ import { defineConfig } from 'vite';
248
+
249
+ export default defineConfig({});
250
+ ```
251
+
252
+ **`index.html`**
253
+ ```html
254
+ <!doctype html>
255
+ <html lang="en">
256
+ <head>
257
+ <meta charset="UTF-8" />
258
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
259
+ <title>My Q App</title>
260
+ <style>
261
+ * { box-sizing: border-box; margin: 0; padding: 0; }
262
+ html, body { height: 100%; }
263
+ #config-container { height: 100%; }
264
+ </style>
265
+ </head>
266
+ <body>
267
+ <div id="config-container"></div>
268
+ <script type="module" src="/src/main.js"></script>
269
+ </body>
270
+ </html>
271
+ ```
272
+
273
+ **`src/main.js`**
274
+ ```js
275
+ import { UniversalAgentConfigGenerator } from 'Q/universal';
276
+ import 'Q/style.css'; // Required — loads all component styles
277
+
278
+ // Mount Q into the container element
279
+ const generator = new UniversalAgentConfigGenerator('#config-container', {
280
+ showEditor: true,
281
+ });
282
+
283
+ const container = document.getElementById('config-container');
284
+
285
+ // Listen for config changes
286
+ container.addEventListener('config-change', (e) => {
287
+ console.log('Config changed:', e.detail);
288
+ });
289
+
290
+ // Listen for download requests
291
+ container.addEventListener('config-download', (e) => {
292
+ console.log('Download requested:', e.detail);
293
+ });
294
+
295
+ // Listen for submit
296
+ container.addEventListener('config-submit', (e) => {
297
+ console.log('Submit clicked:', e.detail);
298
+ // e.detail.yaml — the config as a YAML string
299
+ // e.detail.config — the config as a JS object
300
+ });
301
+ ```
302
+
303
+ ### 4. Run the Application
304
+
305
+ ```bash
306
+ npm run dev
307
+ ```
308
+
309
+ ### Universal Wrapper in Vue
310
+
311
+ ```vue
312
+ <template>
313
+ <div ref="container" style="height: 100%"></div>
314
+ </template>
315
+
316
+ <script>
317
+ import { UniversalAgentConfigGenerator } from 'Q/universal';
318
+ import 'Q/style.css';
319
+
320
+ export default {
321
+ mounted() {
322
+ this.generator = new UniversalAgentConfigGenerator(this.$refs.container, {
323
+ showEditor: true,
324
+ });
325
+
326
+ this.$refs.container.addEventListener('config-submit', (e) => {
327
+ this.$emit('submit', e.detail);
328
+ });
329
+ },
330
+ beforeUnmount() {
331
+ this.generator.destroy();
332
+ },
333
+ };
334
+ </script>
335
+ ```
336
+
337
+ ### Universal Wrapper in Angular
338
+
339
+ ```typescript
340
+ import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
341
+ import { UniversalAgentConfigGenerator } from 'Q/universal';
342
+ import 'Q/style.css';
343
+
344
+ @Component({
345
+ selector: 'app-config-generator',
346
+ template: `<div #container style="height: 100%"></div>`,
347
+ })
348
+ export class ConfigGeneratorComponent implements AfterViewInit, OnDestroy {
349
+ @ViewChild('container') container!: ElementRef;
350
+ private generator!: UniversalAgentConfigGenerator;
351
+
352
+ ngAfterViewInit() {
353
+ this.generator = new UniversalAgentConfigGenerator(this.container.nativeElement, {
354
+ showEditor: true,
355
+ });
356
+
357
+ this.container.nativeElement.addEventListener('config-submit', (e: CustomEvent) => {
358
+ console.log('Submitted:', e.detail);
359
+ });
360
+ }
361
+
362
+ ngOnDestroy() {
363
+ this.generator.destroy();
364
+ }
365
+ }
366
+ ```
367
+
368
+ ---
369
+
370
+ ## API Reference
371
+
372
+ ### React — `AgentConfigGenerator`
373
+
374
+ ```jsx
375
+ import { AgentConfigGenerator } from 'Q';
376
+ ```
377
+
378
+ | Prop | Type | Default | Description |
379
+ | ---------------- | ------------------------------ | ---------------- | --------------------------------------------------------------------------- |
380
+ | `initialConfig` | `object` | auto-derived | Pre-populate with an existing agent config object |
381
+ | `schema` | `object` | built-in schema | Override the default questionnaire schema (MieForms v1.0 format) |
382
+ | `onConfigChange` | `(config: object) => void` | — | Callback fired on every config change |
383
+ | `onDownload` | `(content: string, mode: 'yaml' \| 'json') => void` | — | Callback when the user clicks Download. Receives the serialized config and the format. |
384
+ | `onSubmit` | `(yamlString: string) => void` | — | Callback when the user clicks Submit. Receives the config as a YAML string. Also shows the Submit button. |
385
+ | `showEditor` | `boolean` | `true` | Show/hide the Config Editor tab |
386
+
387
+ ### Universal — `UniversalAgentConfigGenerator`
388
+
389
+ ```js
390
+ import { UniversalAgentConfigGenerator } from 'Q/universal';
391
+ ```
392
+
393
+ #### Constructor
394
+
395
+ ```js
396
+ new UniversalAgentConfigGenerator(target, options?)
397
+ ```
398
+
399
+ | Parameter | Type | Description |
400
+ | ------------------ | ----------------------- | ----------------------------------------------------------- |
401
+ | `target` | `string \| HTMLElement` | CSS selector or DOM element to mount into |
402
+ | `options.initialConfig` | `object` | Pre-populate with an existing agent config |
403
+ | `options.schema` | `object` | Override the default questionnaire schema |
404
+ | `options.showEditor` | `boolean` | Show the Config Editor tab (default: `true`) |
405
+
406
+ #### Methods
407
+
408
+ | Method | Description |
409
+ | ------------------- | ---------------------------------------- |
410
+ | `update(options)` | Merge new options and re-render |
411
+ | `destroy()` | Unmount the component and free resources |
412
+
413
+ #### DOM Events
414
+
415
+ Events are dispatched on the container element. Use `addEventListener` to listen:
416
+
417
+ | Event Name | `e.detail` | Description |
418
+ | ----------------- | -------------------------------------- | ------------------------------------------------ |
419
+ | `config-change` | `object` (the config) | Fired on every config change |
420
+ | `config-download` | `{ content: string, mode: 'yaml' \| 'json' }` | Fired when the user clicks Download |
421
+ | `config-submit` | `{ config: object, yaml: string }` | Fired when the user clicks Submit |
422
+
423
+ ---
424
+
425
+ ## Exported Utilities
426
+
427
+ In addition to the main components, Q exports several utilities:
428
+
429
+ ```js
430
+ import {
431
+ // Components
432
+ AgentConfigGenerator,
433
+ FormBuilder,
434
+ ConfigEditor,
435
+ ToolBuilder,
436
+ Header,
437
+
438
+ // Schema / Config helpers
439
+ defaultSchema, // The built-in questionnaire JSON schema
440
+ deriveDefaultConfig, // (schema) => config object with defaults
441
+ questionnaireToConfig, // Convert schema answers to a config object
442
+ configToQuestionnaire, // Sync a config object back into a schema
443
+ validateConfig, // Validate a config object
444
+ configToYaml, // Convert config to YAML string
445
+ yamlToConfig, // Parse YAML string to config object
446
+ downloadConfig, // Trigger a file download
447
+ copyToClipboard, // Copy text to clipboard
448
+
449
+ // Constants
450
+ TIMEZONES, // Array of timezone strings
451
+ GENERIC_TOOLS, // Built-in MCP tool definitions
452
+ } from 'Q';
453
+ ```
454
+
455
+ The Universal entry also re-exports branding helpers:
456
+
457
+ ```js
458
+ import { brands, generateBrandCSS } from 'Q/universal';
459
+ ```
460
+
461
+ ---
462
+
463
+ ## Styling & CSS
464
+
465
+ Q uses [Tailwind CSS](https://tailwindcss.com/) internally and ships a pre-built CSS file. **You must import the stylesheet** in your application for components to render correctly:
466
+
467
+ ```js
468
+ import 'Q/style.css';
469
+ ```
470
+
471
+ This single import includes:
472
+ - All Tailwind utility classes used by Q components
473
+ - All `@mieweb/ui` component styles
474
+ - Custom animations and hover-state overrides
475
+
476
+ ### Full-Height Layout
477
+
478
+ Q is designed to fill its parent container. Make sure the mount target has a defined height:
479
+
480
+ ```css
481
+ html, body, #root { height: 100%; }
482
+ ```
483
+
484
+ ### Using Q alongside your own Tailwind setup
485
+
486
+ If your host app also uses Tailwind, you can extend your own config with Q's preset:
487
+
488
+ ```js
489
+ // your-app/tailwind.config.js
490
+ import miewebPreset from 'Q/tailwind-config';
491
+
492
+ export default {
493
+ presets: [miewebPreset],
494
+ content: [
495
+ './src/**/*.{js,jsx,ts,tsx}',
496
+ './node_modules/Q/dist/**/*.{js,cjs}', // Scan Q's built output
497
+ ],
498
+ };
499
+ ```
500
+
501
+ ---
502
+
503
+ ## Theming & Brand Customization
504
+
505
+ Q is styled entirely through **CSS custom properties** (variables) defined by `@mieweb/ui`. You can re-theme the entire component by setting these variables on a parent element.
506
+
507
+ ### Built-in Brands
508
+
509
+ `@mieweb/ui` ships with 6 built-in brand themes. Import the desired brand CSS **before** Q's styles:
510
+
511
+ | Brand | Import |
512
+ | ------------------ | ------------------------------------------ |
513
+ | Bluehive (default) | `@mieweb/ui/brands/bluehive.css` |
514
+ | Enterprise Health | `@mieweb/ui/brands/enterprise-health.css` |
515
+ | MIEWeb | `@mieweb/ui/brands/mieweb.css` |
516
+ | Ozwell | `@mieweb/ui/brands/ozwell.css` |
517
+ | WebChart | `@mieweb/ui/brands/webchart.css` |
518
+ | Waggleline | `@mieweb/ui/brands/waggleline.css` |
519
+
520
+ Example (React):
521
+
522
+ ```jsx
523
+ import '@mieweb/ui/brands/enterprise-health.css';
524
+ import 'Q/style.css';
525
+ import { AgentConfigGenerator } from 'Q';
526
+ ```
527
+
528
+ ### Custom Theme via CSS Variables
529
+
530
+ Create your own theme by setting the CSS variables on a parent element or `:root`:
531
+
532
+ ```css
533
+ :root {
534
+ /* Colors */
535
+ --mieweb-background: #ffffff;
536
+ --mieweb-foreground: #0a0a0a;
537
+ --mieweb-card: #ffffff;
538
+ --mieweb-card-foreground: #0a0a0a;
539
+ --mieweb-primary: #2563eb;
540
+ --mieweb-primary-foreground: #ffffff;
541
+ --mieweb-secondary: #f5f5f5;
542
+ --mieweb-secondary-foreground: #171717;
543
+ --mieweb-muted: #f5f5f5;
544
+ --mieweb-muted-foreground: #737373;
545
+ --mieweb-accent: #f5f5f5;
546
+ --mieweb-accent-foreground: #171717;
547
+ --mieweb-destructive: #ef4444;
548
+ --mieweb-destructive-foreground: #ffffff;
549
+ --mieweb-border: #e5e5e5;
550
+ --mieweb-input: #e5e5e5;
551
+ --mieweb-ring: #2563eb;
552
+
553
+ /* Typography */
554
+ --mieweb-font-sans: 'Inter', system-ui, sans-serif;
555
+
556
+ /* Border Radius */
557
+ --mieweb-radius-sm: 0.375rem;
558
+ --mieweb-radius-md: 0.5rem;
559
+ --mieweb-radius-lg: 0.75rem;
560
+ }
561
+ ```
562
+
563
+ ### Scoped Theming
564
+
565
+ Apply different themes to different instances on the same page by scoping CSS variables to a wrapper element:
566
+
567
+ ```html
568
+ <div class="theme-dark" style="
569
+ --mieweb-background: #1a1a1a;
570
+ --mieweb-foreground: #fafafa;
571
+ --mieweb-card: #262626;
572
+ --mieweb-border: #404040;
573
+ ">
574
+ <div id="config-container"></div>
575
+ </div>
576
+ ```
577
+
578
+ ---
579
+
580
+ ## Custom Schemas
581
+
582
+ Q uses a JSON schema format (MieForms v1.0) to define the form fields. You can pass a custom schema to control which fields appear in the Form Builder.
583
+
584
+ ### Schema Structure
585
+
586
+ ```json
587
+ {
588
+ "schemaType": "mieforms-v1.0",
589
+ "title": "My Custom Form",
590
+ "fields": [
591
+ {
592
+ "id": "section-1",
593
+ "fieldType": "section",
594
+ "title": "General Settings",
595
+ "fields": [
596
+ {
597
+ "id": "name",
598
+ "fieldType": "text",
599
+ "question": "Agent Name",
600
+ "answer": "My Agent",
601
+ "required": true
602
+ },
603
+ {
604
+ "id": "provider",
605
+ "fieldType": "dropdown",
606
+ "question": "LLM Provider",
607
+ "answer": "openai",
608
+ "options": ["openai", "anthropic", "google"]
609
+ },
610
+ {
611
+ "id": "enableLogging",
612
+ "fieldType": "check",
613
+ "question": "Enable Logging",
614
+ "answer": false
615
+ },
616
+ {
617
+ "id": "systemPrompt",
618
+ "fieldType": "longtext",
619
+ "question": "System Prompt",
620
+ "answer": ""
621
+ }
622
+ ]
623
+ }
624
+ ]
625
+ }
626
+ ```
627
+
628
+ ### Supported Field Types
629
+
630
+ | Type | Description |
631
+ | ---------- | ----------------------------------------------- |
632
+ | `text` | Single-line text input |
633
+ | `longtext` | Multi-line textarea |
634
+ | `dropdown` | Select dropdown (requires `options` array) |
635
+ | `check` | Boolean checkbox |
636
+ | `section` | Grouping container (contains nested `fields`) |
637
+
638
+ ### Using Nested Keys
639
+
640
+ Use dot-notation in the field `id` to map to nested config keys:
641
+
642
+ ```json
643
+ {
644
+ "id": "twilio.phoneNumber",
645
+ "fieldType": "text",
646
+ "question": "Twilio Phone Number"
647
+ }
648
+ ```
649
+
650
+ This produces:
651
+
652
+ ```yaml
653
+ twilio:
654
+ phoneNumber: "+1234567890"
655
+ ```
656
+
657
+ ### Passing a Custom Schema
658
+
659
+ ```jsx
660
+ import customSchema from './my-schema.json';
661
+
662
+ <AgentConfigGenerator
663
+ schema={customSchema}
664
+ onSubmit={(yaml) => console.log(yaml)}
665
+ />
666
+ ```
667
+
668
+ ---
669
+
670
+ ## Architecture & Flow Diagram
671
+
672
+ ```mermaid
673
+ flowchart TB
674
+ subgraph Host["Host Application"]
675
+ direction TB
676
+ R["React App"]
677
+ U["Universal Wrapper<br/>(Vanilla JS / Vue / Angular)"]
678
+ end
679
+
680
+ subgraph Q["Q Package"]
681
+ direction TB
682
+
683
+ subgraph Entry["Entry Points"]
684
+ RE["Q (React)<br/>import from 'Q'"]
685
+ UE["Q/universal<br/>import from 'Q/universal'"]
686
+ end
687
+
688
+ subgraph Core["Core Components"]
689
+ ACG["AgentConfigGenerator<br/>(orchestrator)"]
690
+ FB["FormBuilder<br/>(questionnaire UI)"]
691
+ CE["ConfigEditor<br/>(Monaco YAML/JSON)"]
692
+ TB["ToolBuilder<br/>(MCP tool editor)"]
693
+ end
694
+
695
+ subgraph Data["Data Layer"]
696
+ CFG["Config State<br/>(React useState)"]
697
+ SCH["Schema State<br/>(MieForms v1.0)"]
698
+ YAML["YAML/JSON<br/>Output Sync"]
699
+ end
700
+
701
+ subgraph Style["Styling"]
702
+ CSS["Q/style.css<br/>(Tailwind bundle)"]
703
+ VAR["CSS Variables<br/>(--mieweb-*)"]
704
+ BRAND["Brand Themes<br/>(@mieweb/ui)"]
705
+ end
706
+ end
707
+
708
+ R -->|"import { AgentConfigGenerator }"| RE
709
+ U -->|"new UniversalAgentConfigGenerator()"| UE
710
+ UE -->|"wraps with createRoot"| ACG
711
+ RE --> ACG
712
+
713
+ ACG --> FB
714
+ ACG --> CE
715
+ ACG --> TB
716
+
717
+ FB -->|"form answers"| CFG
718
+ CE -->|"editor changes"| CFG
719
+ TB -->|"tool definitions"| CFG
720
+ CFG -->|"sync"| YAML
721
+ CFG <-->|"bidirectional"| SCH
722
+
723
+ BRAND --> VAR
724
+ VAR --> CSS
725
+
726
+ ACG -->|"onConfigChange"| Host
727
+ ACG -->|"onSubmit (YAML)"| Host
728
+ ACG -->|"onDownload"| Host
729
+ ```
730
+
731
+ ### Data Flow
732
+
733
+ ```mermaid
734
+ sequenceDiagram
735
+ participant User
736
+ participant FormBuilder
737
+ participant ConfigState
738
+ participant ConfigEditor
739
+ participant HostApp
740
+
741
+ User->>FormBuilder: Fill out form fields
742
+ FormBuilder->>ConfigState: Update config object
743
+ ConfigState->>ConfigEditor: Sync YAML/JSON strings
744
+ ConfigState->>HostApp: onConfigChange(config)
745
+
746
+ User->>ConfigEditor: Edit YAML/JSON directly
747
+ ConfigEditor->>ConfigState: Parse & update config
748
+ ConfigState->>FormBuilder: Re-render with new values
749
+
750
+ User->>HostApp: Click Submit
751
+ HostApp->>ConfigState: Read yamlOutput
752
+ ConfigState-->>HostApp: onSubmit(yamlString)
753
+ ```
754
+
755
+ ### Component Tabs
756
+
757
+ ```mermaid
758
+ stateDiagram-v2
759
+ [*] --> FormBuilder
760
+
761
+ FormBuilder --> ConfigEditor: Switch tab
762
+ FormBuilder --> ToolBuilder: Switch tab
763
+ ConfigEditor --> FormBuilder: Switch tab
764
+ ConfigEditor --> ToolBuilder: Switch tab
765
+ ToolBuilder --> FormBuilder: Switch tab
766
+ ToolBuilder --> ConfigEditor: Switch tab
767
+
768
+ FormBuilder --> SchemaEditor: Click "Customize Form"
769
+ SchemaEditor --> FormBuilder: Click "Back to Form"
770
+
771
+ state FormBuilder {
772
+ [*] --> RenderForm
773
+ RenderForm: Questionnaire UI
774
+ }
775
+
776
+ state ConfigEditor {
777
+ [*] --> YAML
778
+ YAML --> JSON: Toggle
779
+ JSON --> YAML: Toggle
780
+ }
781
+
782
+ state ToolBuilder {
783
+ [*] --> ToolList
784
+ ToolList: MCP Tool Definitions
785
+ }
786
+ ```
787
+
788
+ ---
789
+
790
+ ## Project Structure
791
+
792
+ ```
793
+ Q/
794
+ ├── dist/ # Built output (generated)
795
+ │ ├── index.js / index.cjs # React component library
796
+ │ ├── universal.js / .cjs # Framework-agnostic wrapper
797
+ │ └── style.css # Pre-built Tailwind CSS
798
+ ├── src/
799
+ │ ├── index.js # React entry — public exports
800
+ │ ├── universal.jsx # Universal wrapper class
801
+ │ ├── index.css # Tailwind directives + custom styles
802
+ │ ├── components/
803
+ │ │ ├── AgentConfigGenerator.jsx # Main orchestrator component
804
+ │ │ ├── FormBuilder.jsx # Questionnaire form renderer
805
+ │ │ ├── ConfigEditor.jsx # Monaco-based YAML/JSON editor
806
+ │ │ └── ToolBuilder.jsx # MCP tool definition editor
807
+ │ ├── schemas/
808
+ │ │ └── agent-config-questionnaire.json # Default form schema
809
+ │ ├── constants/
810
+ │ │ └── defaults.js # Timezones, generic tools
811
+ │ └── utils/
812
+ │ ├── configHelpers.js # YAML/JSON conversion, download, clipboard
813
+ │ └── transformers.js # Schema ↔ config transformations
814
+ ├── package.json
815
+ ├── vite.config.js # Dev server config
816
+ ├── vite.lib.config.js # Library build config
817
+ ├── tailwind.config.js # Tailwind CSS config with @mieweb/ui preset
818
+ ├── postcss.config.js # PostCSS config (Tailwind + Autoprefixer)
819
+ └── .npmrc # npm config (legacy-peer-deps)
820
+ ```
821
+
822
+ ---
823
+
824
+ ## Development
825
+
826
+ ### Running the Dev Server
827
+
828
+ ```bash
829
+ # Clone the repo
830
+ git clone https://github.com/avagu-mie/Q.git && cd Q
831
+
832
+ # Install dependencies
833
+ npm install
834
+
835
+ # Start the dev server with both React and Universal demo pages
836
+ npm run dev # Opens index.html (default demo)
837
+ npm run dev:react # Opens the React-specific demo page
838
+ npm run dev:universal # Opens the Universal demo page
839
+ ```
840
+
841
+ ### Building the Library
842
+
843
+ ```bash
844
+ # Build the distributable library files
845
+ npm run build:lib
846
+
847
+ # Full prepare (build + CSS) — runs automatically on npm install from GitHub
848
+ npm run prepare
849
+ ```
850
+
851
+ ### Key Scripts
852
+
853
+ | Script | Description |
854
+ | ----------------- | ------------------------------------------------------------- |
855
+ | `npm run dev` | Start Vite dev server with HMR |
856
+ | `npm run build` | Production build of the demo app |
857
+ | `npm run build:lib` | Build the library (`dist/index.js`, `dist/universal.js`) |
858
+ | `npm run prepare` | Full library build + Tailwind CSS compilation |
859
+ | `npm run storybook` | Start Storybook for component development |
860
+
861
+ ---
862
+
863
+ ## Troubleshooting
864
+
865
+ ### `npm install` fails with peer dependency errors
866
+
867
+ Q uses `legacy-peer-deps=true` in its `.npmrc` to handle peer dependency conflicts between Storybook (which expects React 18) and the library (which supports React 19). If you encounter peer dep issues in your host app, create an `.npmrc` in your project root:
868
+
869
+ ```
870
+ legacy-peer-deps=true
871
+ ```
872
+
873
+ ### Styles not loading / unstyled components
874
+
875
+ Make sure you import the CSS file:
876
+
877
+ ```js
878
+ import 'Q/style.css';
879
+ ```
880
+
881
+ This import is **required**. Without it, components will render without any styling.
882
+
883
+ ### Component doesn't fill the page
884
+
885
+ Q renders to fill its parent container. Ensure the parent element has an explicit height:
886
+
887
+ ```css
888
+ html, body, #root { height: 100%; }
889
+ ```
890
+
891
+ ### Monaco Editor not loading
892
+
893
+ The Monaco editor (used in the Config Editor tab) is loaded asynchronously. Ensure your bundler supports dynamic imports (all modern bundlers do). If using a CSP (Content Security Policy), make sure `worker-src` allows blob URLs.
894
+
895
+ ### Build errors with `ERR_PACKAGE_PATH_NOT_EXPORTED`
896
+
897
+ If you see export map errors, check that you're importing from the correct path:
898
+
899
+ ```js
900
+ // ✅ Correct
901
+ import { AgentConfigGenerator } from 'Q';
902
+ import { UniversalAgentConfigGenerator } from 'Q/universal';
903
+ import 'Q/style.css';
904
+
905
+ // ❌ Wrong — don't import from dist/ directly
906
+ import { AgentConfigGenerator } from 'Q/dist/index.js';
907
+ ```
908
+
909
+ ---
910
+
911
+ ## Sample Output
912
+
913
+ Here's an example of the YAML config that Q generates with the default schema:
914
+
915
+ ```yaml
916
+ _id: ""
917
+ name: New Agent Config
918
+ timezone: America/New_York
919
+ description: Agent Assistant Description
920
+ twilio:
921
+ phoneNumber: ""
922
+ accountSid: ""
923
+ authToken: ""
924
+ officeOpeningTime: 8
925
+ officeClosingTime: 17
926
+ systemPrompt: ""
927
+ tools: []
928
+ ```
929
+
930
+ Each field in the form maps directly to a key in this output. Nested keys (like `twilio.phoneNumber`) are expanded into nested YAML objects. The Tool Builder tab adds entries to the `tools` array using the MCP `inputSchema` format.
931
+
932
+