@lantos1618/better-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/lib/aui/README.md +136 -0
  4. package/lib/aui/__tests__/aui-complete.test.ts +251 -0
  5. package/lib/aui/__tests__/aui-comprehensive.test.ts +376 -0
  6. package/lib/aui/__tests__/aui-concise.test.ts +278 -0
  7. package/lib/aui/__tests__/aui-integration.test.ts +309 -0
  8. package/lib/aui/__tests__/aui-simple.test.ts +116 -0
  9. package/lib/aui/__tests__/aui.test.ts +269 -0
  10. package/lib/aui/__tests__/concise-api.test.ts +165 -0
  11. package/lib/aui/__tests__/core.test.ts +265 -0
  12. package/lib/aui/__tests__/simple-api.test.ts +200 -0
  13. package/lib/aui/ai-assistant.ts +408 -0
  14. package/lib/aui/ai-control.ts +353 -0
  15. package/lib/aui/client/use-aui.ts +55 -0
  16. package/lib/aui/client-control.ts +551 -0
  17. package/lib/aui/client-executor.ts +417 -0
  18. package/lib/aui/components/ToolRenderer.tsx +22 -0
  19. package/lib/aui/core.ts +137 -0
  20. package/lib/aui/demo.tsx +89 -0
  21. package/lib/aui/examples/ai-complete-demo.tsx +359 -0
  22. package/lib/aui/examples/ai-control-demo.tsx +356 -0
  23. package/lib/aui/examples/ai-control-tools.ts +308 -0
  24. package/lib/aui/examples/concise-api.tsx +153 -0
  25. package/lib/aui/examples/index.tsx +163 -0
  26. package/lib/aui/examples/quick-demo.tsx +91 -0
  27. package/lib/aui/examples/simple-demo.tsx +71 -0
  28. package/lib/aui/examples/simple-tools.tsx +160 -0
  29. package/lib/aui/examples/user-api.tsx +208 -0
  30. package/lib/aui/examples/user-requested.tsx +174 -0
  31. package/lib/aui/examples/weather-search-tools.tsx +119 -0
  32. package/lib/aui/examples.tsx +367 -0
  33. package/lib/aui/hooks/useAUITool.ts +142 -0
  34. package/lib/aui/hooks/useAUIToolEnhanced.ts +343 -0
  35. package/lib/aui/hooks/useAUITools.ts +195 -0
  36. package/lib/aui/index.ts +156 -0
  37. package/lib/aui/provider.tsx +45 -0
  38. package/lib/aui/server-control.ts +386 -0
  39. package/lib/aui/server-executor.ts +165 -0
  40. package/lib/aui/server.ts +167 -0
  41. package/lib/aui/tool-registry.ts +380 -0
  42. package/lib/aui/tools/advanced-examples.tsx +86 -0
  43. package/lib/aui/tools/ai-complete.ts +375 -0
  44. package/lib/aui/tools/api-tools.tsx +230 -0
  45. package/lib/aui/tools/data-tools.tsx +232 -0
  46. package/lib/aui/tools/dom-tools.tsx +202 -0
  47. package/lib/aui/tools/examples.ts +43 -0
  48. package/lib/aui/tools/file-tools.tsx +202 -0
  49. package/lib/aui/tools/form-tools.tsx +233 -0
  50. package/lib/aui/tools/index.ts +8 -0
  51. package/lib/aui/tools/navigation-tools.tsx +172 -0
  52. package/lib/aui/tools/notification-tools.ts +213 -0
  53. package/lib/aui/tools/state-tools.tsx +209 -0
  54. package/lib/aui/types.ts +47 -0
  55. package/lib/aui/vercel-ai.ts +100 -0
  56. package/package.json +51 -0
@@ -0,0 +1,359 @@
1
+ import React from 'react';
2
+ import aui from '../index';
3
+ import { z } from 'zod';
4
+ import { aiControlSystem } from '../ai-control';
5
+ import { clientControlSystem } from '../client-control';
6
+
7
+ // Simple weather tool - server execution
8
+ const weatherTool = aui
9
+ .tool('weather')
10
+ .input(z.object({ city: z.string() }))
11
+ .execute(async ({ input }) => {
12
+ // Simulated API call
13
+ const temps = { 'New York': 72, 'London': 65, 'Tokyo': 78 };
14
+ return {
15
+ temp: temps[input.city as keyof typeof temps] || 70,
16
+ city: input.city,
17
+ conditions: 'Partly cloudy'
18
+ };
19
+ })
20
+ .render(({ data }) => (
21
+ <div className="weather-widget p-4 bg-blue-50 rounded">
22
+ <h3>{data.city}</h3>
23
+ <p className="text-2xl">{data.temp}°F</p>
24
+ <p>{data.conditions}</p>
25
+ </div>
26
+ ));
27
+
28
+ // Complex search tool with client caching
29
+ const searchTool = aui
30
+ .tool('search')
31
+ .input(z.object({
32
+ query: z.string(),
33
+ limit: z.number().default(10)
34
+ }))
35
+ .execute(async ({ input }) => {
36
+ // Server-side database search
37
+ const results = await fetch('/api/search', {
38
+ method: 'POST',
39
+ body: JSON.stringify(input)
40
+ }).then(r => r.json());
41
+ return results;
42
+ })
43
+ .clientExecute(async ({ input, ctx }) => {
44
+ // Check cache first
45
+ const cacheKey = `search:${input.query}:${input.limit}`;
46
+ const cached = ctx.cache.get(cacheKey);
47
+
48
+ if (cached && Date.now() - cached.timestamp < 60000) {
49
+ return cached.data;
50
+ }
51
+
52
+ // Fetch from server
53
+ const data = await ctx.fetch('/api/tools/search', {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify(input)
57
+ }).then(r => r.json());
58
+
59
+ // Cache the result
60
+ ctx.cache.set(cacheKey, { data, timestamp: Date.now() });
61
+ return data;
62
+ })
63
+ .render(({ data, loading }) => (
64
+ <div className="search-results">
65
+ {loading ? (
66
+ <div>Searching...</div>
67
+ ) : (
68
+ <ul>
69
+ {data?.results?.map((item: any, i: number) => (
70
+ <li key={i}>{item.title}</li>
71
+ ))}
72
+ </ul>
73
+ )}
74
+ </div>
75
+ ));
76
+
77
+ // AI-controlled form automation
78
+ const formAutomationTool = aui
79
+ .tool('form-automation')
80
+ .input(z.object({
81
+ formId: z.string(),
82
+ fields: z.record(z.any()),
83
+ autoSubmit: z.boolean().default(false)
84
+ }))
85
+ .clientExecute(async ({ input }) => {
86
+ const form = document.getElementById(input.formId) as HTMLFormElement;
87
+ if (!form) throw new Error('Form not found');
88
+
89
+ // Fill form fields
90
+ Object.entries(input.fields).forEach(([name, value]) => {
91
+ const field = form.elements.namedItem(name) as HTMLInputElement;
92
+ if (field) {
93
+ field.value = String(value);
94
+ field.dispatchEvent(new Event('input', { bubbles: true }));
95
+ }
96
+ });
97
+
98
+ // Auto-submit if requested
99
+ if (input.autoSubmit) {
100
+ form.submit();
101
+ return { submitted: true, fields: input.fields };
102
+ }
103
+
104
+ return { filled: true, fields: input.fields };
105
+ })
106
+ .render(({ data }) => (
107
+ <div className="p-2 bg-green-50 rounded">
108
+ {data.submitted ? 'Form submitted' : 'Form filled'}
109
+ <pre>{JSON.stringify(data.fields, null, 2)}</pre>
110
+ </div>
111
+ ));
112
+
113
+ // Data visualization tool
114
+ const dataVisualizationTool = aui
115
+ .tool('data-viz')
116
+ .input(z.object({
117
+ type: z.enum(['chart', 'table', 'metrics']),
118
+ data: z.array(z.record(z.any())),
119
+ config: z.object({
120
+ title: z.string().optional(),
121
+ xAxis: z.string().optional(),
122
+ yAxis: z.string().optional()
123
+ }).optional()
124
+ }))
125
+ .execute(async ({ input }) => {
126
+ // Process data on server
127
+ return {
128
+ type: input.type,
129
+ processedData: input.data,
130
+ config: input.config
131
+ };
132
+ })
133
+ .render(({ data }) => {
134
+ switch (data.type) {
135
+ case 'metrics':
136
+ return (
137
+ <div className="metrics-grid grid grid-cols-3 gap-4">
138
+ {data.processedData.map((metric: any, i: number) => (
139
+ <div key={i} className="metric-card p-4 bg-gray-50 rounded">
140
+ <h4>{metric.label}</h4>
141
+ <p className="text-2xl font-bold">{metric.value}</p>
142
+ </div>
143
+ ))}
144
+ </div>
145
+ );
146
+ case 'table':
147
+ return (
148
+ <table className="data-table w-full">
149
+ <thead>
150
+ <tr>
151
+ {Object.keys(data.processedData[0] || {}).map(key => (
152
+ <th key={key}>{key}</th>
153
+ ))}
154
+ </tr>
155
+ </thead>
156
+ <tbody>
157
+ {data.processedData.map((row: any, i: number) => (
158
+ <tr key={i}>
159
+ {Object.values(row).map((val: any, j: number) => (
160
+ <td key={j}>{String(val)}</td>
161
+ ))}
162
+ </tr>
163
+ ))}
164
+ </tbody>
165
+ </table>
166
+ );
167
+ default:
168
+ return <div>Chart visualization placeholder</div>;
169
+ }
170
+ });
171
+
172
+ // Backend control tool for database operations
173
+ const databaseTool = aui
174
+ .tool('database')
175
+ .input(z.object({
176
+ operation: z.enum(['query', 'insert', 'update', 'delete']),
177
+ table: z.string(),
178
+ data: z.any().optional(),
179
+ where: z.record(z.any()).optional(),
180
+ select: z.array(z.string()).optional()
181
+ }))
182
+ .execute(async ({ input, ctx }) => {
183
+ // This would connect to your actual database
184
+ // For demo, returning mock data
185
+ switch (input.operation) {
186
+ case 'query':
187
+ return {
188
+ rows: [
189
+ { id: 1, name: 'Item 1', created: new Date().toISOString() },
190
+ { id: 2, name: 'Item 2', created: new Date().toISOString() }
191
+ ],
192
+ count: 2
193
+ };
194
+ case 'insert':
195
+ return { id: Math.random(), inserted: true };
196
+ case 'update':
197
+ return { updated: 1 };
198
+ case 'delete':
199
+ return { deleted: 1 };
200
+ default:
201
+ throw new Error('Unknown operation');
202
+ }
203
+ })
204
+ .render(({ data }) => (
205
+ <div className="database-result">
206
+ <pre>{JSON.stringify(data, null, 2)}</pre>
207
+ </div>
208
+ ));
209
+
210
+ // File operations tool (server-side only)
211
+ const fileOperationsTool = aui
212
+ .tool('file-ops')
213
+ .input(z.object({
214
+ action: z.enum(['read', 'write', 'list', 'delete']),
215
+ path: z.string(),
216
+ content: z.string().optional(),
217
+ encoding: z.enum(['utf8', 'base64']).default('utf8')
218
+ }))
219
+ .execute(async ({ input, ctx }) => {
220
+ // Only allow on server
221
+ if (!ctx?.isServer) {
222
+ throw new Error('File operations only available on server');
223
+ }
224
+
225
+ // Mock file operations
226
+ switch (input.action) {
227
+ case 'read':
228
+ return { content: 'File content here', path: input.path };
229
+ case 'write':
230
+ return { written: true, path: input.path, size: input.content?.length };
231
+ case 'list':
232
+ return { files: ['file1.txt', 'file2.json'], path: input.path };
233
+ case 'delete':
234
+ return { deleted: true, path: input.path };
235
+ default:
236
+ throw new Error('Unknown action');
237
+ }
238
+ });
239
+
240
+ // AI Control Demo Component
241
+ export function AIControlDemo() {
242
+ const [results, setResults] = React.useState<any[]>([]);
243
+
244
+ const executeAICommand = async (command: string) => {
245
+ // Parse AI command and execute appropriate tool
246
+ const lowerCommand = command.toLowerCase();
247
+
248
+ try {
249
+ let result: any;
250
+
251
+ if (lowerCommand.includes('weather')) {
252
+ const city = command.match(/weather (?:in|for) (.+)/i)?.[1] || 'New York';
253
+ result = await aui.execute('weather', { city });
254
+ } else if (lowerCommand.includes('search')) {
255
+ const query = command.match(/search (?:for )?"(.+)"/i)?.[1] || command;
256
+ result = await aui.execute('search', { query, limit: 5 });
257
+ } else if (lowerCommand.includes('fill form')) {
258
+ result = await aui.execute('form-automation', {
259
+ formId: 'demo-form',
260
+ fields: { name: 'AI User', email: 'ai@example.com' },
261
+ autoSubmit: false
262
+ });
263
+ } else if (lowerCommand.includes('database')) {
264
+ result = await aui.execute('database', {
265
+ operation: 'query',
266
+ table: 'users',
267
+ select: ['id', 'name', 'created']
268
+ });
269
+ } else if (lowerCommand.includes('visualize')) {
270
+ result = await aui.execute('data-viz', {
271
+ type: 'metrics',
272
+ data: [
273
+ { label: 'Users', value: 1234 },
274
+ { label: 'Sessions', value: 5678 },
275
+ { label: 'Revenue', value: '$9,012' }
276
+ ]
277
+ });
278
+ }
279
+
280
+ setResults(prev => [...prev, { command, result, timestamp: new Date() }]);
281
+ } catch (error) {
282
+ setResults(prev => [...prev, {
283
+ command,
284
+ error: error instanceof Error ? error.message : 'Unknown error',
285
+ timestamp: new Date()
286
+ }]);
287
+ }
288
+ };
289
+
290
+ return (
291
+ <div className="ai-control-demo p-6">
292
+ <h2 className="text-2xl font-bold mb-4">AI Control System Demo</h2>
293
+
294
+ <div className="command-examples mb-4 p-4 bg-gray-50 rounded">
295
+ <h3 className="font-semibold mb-2">Try these AI commands:</h3>
296
+ <ul className="list-disc list-inside space-y-1">
297
+ <li>Get weather in Tokyo</li>
298
+ <li>Search for &quot;machine learning&quot;</li>
299
+ <li>Fill form with test data</li>
300
+ <li>Query database users table</li>
301
+ <li>Visualize metrics dashboard</li>
302
+ </ul>
303
+ </div>
304
+
305
+ <div className="command-input mb-4">
306
+ <input
307
+ type="text"
308
+ className="w-full p-2 border rounded"
309
+ placeholder="Enter AI command..."
310
+ onKeyPress={(e) => {
311
+ if (e.key === 'Enter') {
312
+ executeAICommand((e.target as HTMLInputElement).value);
313
+ (e.target as HTMLInputElement).value = '';
314
+ }
315
+ }}
316
+ />
317
+ </div>
318
+
319
+ <div className="results space-y-4">
320
+ {results.map((r, i) => (
321
+ <div key={i} className="result-item p-4 border rounded">
322
+ <div className="font-mono text-sm text-gray-600 mb-2">
323
+ {r.timestamp.toLocaleTimeString()} - {r.command}
324
+ </div>
325
+ {r.error ? (
326
+ <div className="text-red-600">Error: {r.error}</div>
327
+ ) : (
328
+ <div className="result-content">
329
+ <pre>{JSON.stringify(r.result, null, 2)}</pre>
330
+ </div>
331
+ )}
332
+ </div>
333
+ ))}
334
+ </div>
335
+
336
+ <form id="demo-form" className="hidden">
337
+ <input name="name" type="text" />
338
+ <input name="email" type="email" />
339
+ </form>
340
+ </div>
341
+ );
342
+ }
343
+
344
+ // Export all tools for registration
345
+ export const aiCompleteDemoTools = {
346
+ weatherTool,
347
+ searchTool,
348
+ formAutomationTool,
349
+ dataVisualizationTool,
350
+ databaseTool,
351
+ fileOperationsTool
352
+ };
353
+
354
+ // Register all tools with AI control system
355
+ Object.values(aiCompleteDemoTools).forEach(tool => {
356
+ aiControlSystem.register(tool as any);
357
+ });
358
+
359
+ export default AIControlDemo;