codebakers 1.0.45 → 2.0.1

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 (82) hide show
  1. package/README.md +275 -60
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +4260 -0
  4. package/install.bat +9 -0
  5. package/package.json +71 -115
  6. package/src/channels/discord.ts +5 -0
  7. package/src/channels/slack.ts +5 -0
  8. package/src/channels/sms.ts +4 -0
  9. package/src/channels/telegram.ts +5 -0
  10. package/src/channels/whatsapp.ts +7 -0
  11. package/src/commands/check.ts +365 -0
  12. package/src/commands/code.ts +684 -0
  13. package/src/commands/connect.ts +12 -0
  14. package/src/commands/deploy.ts +414 -0
  15. package/src/commands/design.ts +298 -0
  16. package/src/commands/fix.ts +20 -0
  17. package/src/commands/gateway.ts +604 -0
  18. package/src/commands/generate.ts +178 -0
  19. package/src/commands/init.ts +574 -0
  20. package/src/commands/learn.ts +36 -0
  21. package/src/commands/security.ts +102 -0
  22. package/src/commands/setup.ts +448 -0
  23. package/src/commands/status.ts +56 -0
  24. package/src/index.ts +278 -0
  25. package/src/patterns/loader.ts +337 -0
  26. package/src/services/github.ts +61 -0
  27. package/src/services/supabase.ts +147 -0
  28. package/src/services/vercel.ts +61 -0
  29. package/src/utils/claude-md.ts +287 -0
  30. package/src/utils/config.ts +282 -0
  31. package/src/utils/updates.ts +27 -0
  32. package/tsconfig.json +17 -10
  33. package/.vscodeignore +0 -18
  34. package/LICENSE +0 -21
  35. package/codebakers-1.0.0.vsix +0 -0
  36. package/codebakers-1.0.10.vsix +0 -0
  37. package/codebakers-1.0.11.vsix +0 -0
  38. package/codebakers-1.0.12.vsix +0 -0
  39. package/codebakers-1.0.13.vsix +0 -0
  40. package/codebakers-1.0.14.vsix +0 -0
  41. package/codebakers-1.0.15.vsix +0 -0
  42. package/codebakers-1.0.16.vsix +0 -0
  43. package/codebakers-1.0.17.vsix +0 -0
  44. package/codebakers-1.0.18.vsix +0 -0
  45. package/codebakers-1.0.19.vsix +0 -0
  46. package/codebakers-1.0.20.vsix +0 -0
  47. package/codebakers-1.0.21.vsix +0 -0
  48. package/codebakers-1.0.22.vsix +0 -0
  49. package/codebakers-1.0.23.vsix +0 -0
  50. package/codebakers-1.0.24.vsix +0 -0
  51. package/codebakers-1.0.25.vsix +0 -0
  52. package/codebakers-1.0.26.vsix +0 -0
  53. package/codebakers-1.0.27.vsix +0 -0
  54. package/codebakers-1.0.28.vsix +0 -0
  55. package/codebakers-1.0.29.vsix +0 -0
  56. package/codebakers-1.0.30.vsix +0 -0
  57. package/codebakers-1.0.31.vsix +0 -0
  58. package/codebakers-1.0.32.vsix +0 -0
  59. package/codebakers-1.0.35.vsix +0 -0
  60. package/codebakers-1.0.36.vsix +0 -0
  61. package/codebakers-1.0.37.vsix +0 -0
  62. package/codebakers-1.0.38.vsix +0 -0
  63. package/codebakers-1.0.39.vsix +0 -0
  64. package/codebakers-1.0.40.vsix +0 -0
  65. package/codebakers-1.0.41.vsix +0 -0
  66. package/codebakers-1.0.42.vsix +0 -0
  67. package/codebakers-1.0.43.vsix +0 -0
  68. package/codebakers-1.0.44.vsix +0 -0
  69. package/codebakers-1.0.45.vsix +0 -0
  70. package/dist/extension.js +0 -1394
  71. package/esbuild.js +0 -63
  72. package/media/icon.png +0 -0
  73. package/media/icon.svg +0 -7
  74. package/nul +0 -1
  75. package/preview.html +0 -547
  76. package/src/ChatPanelProvider.ts +0 -1815
  77. package/src/ChatViewProvider.ts +0 -749
  78. package/src/CodeBakersClient.ts +0 -1146
  79. package/src/CodeValidator.ts +0 -645
  80. package/src/FileOperations.ts +0 -410
  81. package/src/ProjectContext.ts +0 -526
  82. package/src/extension.ts +0 -332
@@ -1,749 +0,0 @@
1
- import * as vscode from 'vscode';
2
- import { CodeBakersClient } from './CodeBakersClient';
3
- import { ProjectContext } from './ProjectContext';
4
-
5
- interface Message {
6
- role: 'user' | 'assistant';
7
- content: string;
8
- timestamp: Date;
9
- }
10
-
11
- export class ChatViewProvider implements vscode.WebviewViewProvider {
12
- private _view?: vscode.WebviewView;
13
- private _messages: Message[] = [];
14
- private _conversationSummary: string = '';
15
-
16
- constructor(
17
- private readonly context: vscode.ExtensionContext,
18
- private readonly client: CodeBakersClient,
19
- private readonly projectContext: ProjectContext
20
- ) {}
21
-
22
- /**
23
- * Refresh the webview after login/logout
24
- */
25
- refresh() {
26
- if (this._view) {
27
- this._initializeStatus();
28
- this._updateWebview();
29
- }
30
- }
31
-
32
- resolveWebviewView(
33
- webviewView: vscode.WebviewView,
34
- _context: vscode.WebviewViewResolveContext,
35
- _token: vscode.CancellationToken
36
- ) {
37
- this._view = webviewView;
38
-
39
- webviewView.webview.options = {
40
- enableScripts: true,
41
- localResourceRoots: [this.context.extensionUri]
42
- };
43
-
44
- webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
45
-
46
- // Handle messages from the webview
47
- webviewView.webview.onDidReceiveMessage(async (data) => {
48
- switch (data.type) {
49
- case 'sendMessage':
50
- await this.sendMessage(data.message);
51
- break;
52
- case 'clearChat':
53
- this._messages = [];
54
- this._conversationSummary = '';
55
- this._updateWebview();
56
- break;
57
- case 'runTool':
58
- await this._executeTool(data.tool);
59
- break;
60
- }
61
- });
62
-
63
- // Initialize plan and health on load (non-blocking)
64
- this._initializeStatus();
65
- }
66
-
67
- private async _initializeStatus() {
68
- if (!this._view) return;
69
-
70
- try {
71
- // Get plan info (sync, always works)
72
- const planInfo = this.client.getPlanInfo();
73
- this._view.webview.postMessage({
74
- type: 'updatePlan',
75
- plan: planInfo.plan
76
- });
77
-
78
- // Only try to get health if user is logged in
79
- if (!this.client.hasSessionToken()) {
80
- // Show default health for non-logged in users
81
- this._view.webview.postMessage({
82
- type: 'updateHealth',
83
- health: 0,
84
- score: 0
85
- });
86
- return;
87
- }
88
-
89
- // Get health status (async, might fail - that's OK)
90
- try {
91
- const health = await this.client.guardianStatus();
92
- this._view.webview.postMessage({
93
- type: 'updateHealth',
94
- health: health.data?.health || 85,
95
- score: health.data?.health || 85
96
- });
97
- } catch (healthError) {
98
- // Health check failed - show default
99
- console.warn('Health check failed:', healthError);
100
- this._view.webview.postMessage({
101
- type: 'updateHealth',
102
- health: 85,
103
- score: 85
104
- });
105
- }
106
- } catch (error) {
107
- console.error('Failed to initialize status:', error);
108
- }
109
- }
110
-
111
- private async _executeTool(toolName: string) {
112
- if (!this._view) return;
113
-
114
- try {
115
- this._view.webview.postMessage({ type: 'typing', isTyping: true });
116
-
117
- const result = await this.client.executeTool(toolName, {});
118
-
119
- this._view.webview.postMessage({
120
- type: 'toolResult',
121
- tool: toolName,
122
- result: result.data || result
123
- });
124
-
125
- // If it's a health check, update the health bar
126
- if (toolName === 'guardian_status' && result.data?.health) {
127
- this._view.webview.postMessage({
128
- type: 'updateHealth',
129
- health: result.data.health,
130
- score: result.data.health
131
- });
132
- }
133
- } catch (error) {
134
- this._view.webview.postMessage({
135
- type: 'toolResult',
136
- tool: toolName,
137
- result: { error: error instanceof Error ? error.message : 'Tool execution failed' }
138
- });
139
- } finally {
140
- this._view?.webview.postMessage({ type: 'typing', isTyping: false });
141
- }
142
- }
143
-
144
- async sendMessage(userMessage: string) {
145
- if (!this._view) return;
146
-
147
- // Add user message to history
148
- this._messages.push({
149
- role: 'user',
150
- content: userMessage,
151
- timestamp: new Date()
152
- });
153
- this._updateWebview();
154
-
155
- try {
156
- // Show typing indicator
157
- this._view.webview.postMessage({ type: 'typing', isTyping: true });
158
-
159
- // Get project context for perfect recall
160
- const projectState = await this.projectContext.getProjectState();
161
-
162
- // Build the context-aware prompt
163
- const contextualizedMessages = await this._buildContextualizedMessages(userMessage, projectState);
164
-
165
- // Call Claude via our API (with pattern enforcement)
166
- const response = await this.client.chat(contextualizedMessages, projectState);
167
-
168
- // Add assistant response
169
- this._messages.push({
170
- role: 'assistant',
171
- content: response.content,
172
- timestamp: new Date()
173
- });
174
-
175
- // Update project context with any new information
176
- if (response.projectUpdates) {
177
- await this.projectContext.applyUpdates(response.projectUpdates);
178
- }
179
-
180
- // Check if we need to summarize (context getting large)
181
- if (this._messages.length > 20) {
182
- await this._summarizeConversation();
183
- }
184
-
185
- } catch (error) {
186
- this._messages.push({
187
- role: 'assistant',
188
- content: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
189
- timestamp: new Date()
190
- });
191
- } finally {
192
- this._view?.webview.postMessage({ type: 'typing', isTyping: false });
193
- this._updateWebview();
194
- }
195
- }
196
-
197
- private async _buildContextualizedMessages(userMessage: string, projectState: any): Promise<any[]> {
198
- const messages: any[] = [];
199
-
200
- // Always include summary if we have one (perfect recall)
201
- if (this._conversationSummary) {
202
- messages.push({
203
- role: 'system',
204
- content: `Previous conversation summary:\n${this._conversationSummary}`
205
- });
206
- }
207
-
208
- // Include relevant project context
209
- if (projectState) {
210
- messages.push({
211
- role: 'system',
212
- content: `Current project state:\n${JSON.stringify(projectState, null, 2)}`
213
- });
214
- }
215
-
216
- // Include recent messages (last 10 for context)
217
- const recentMessages = this._messages.slice(-10);
218
- for (const msg of recentMessages) {
219
- messages.push({
220
- role: msg.role,
221
- content: msg.content
222
- });
223
- }
224
-
225
- return messages;
226
- }
227
-
228
- private async _summarizeConversation() {
229
- // Summarize older messages to maintain context without using all tokens
230
- const oldMessages = this._messages.slice(0, -10);
231
- if (oldMessages.length === 0) return;
232
-
233
- const summaryPrompt = `Summarize these conversation messages, keeping key decisions and context:\n${
234
- oldMessages.map(m => `${m.role}: ${m.content}`).join('\n')
235
- }`;
236
-
237
- try {
238
- const summary = await this.client.summarize(summaryPrompt);
239
- this._conversationSummary = summary;
240
-
241
- // Keep only recent messages
242
- this._messages = this._messages.slice(-10);
243
- } catch (error) {
244
- console.error('Failed to summarize conversation:', error);
245
- }
246
- }
247
-
248
- private _updateWebview() {
249
- if (!this._view) return;
250
-
251
- this._view.webview.postMessage({
252
- type: 'updateMessages',
253
- messages: this._messages.map(m => ({
254
- role: m.role,
255
- content: m.content,
256
- timestamp: m.timestamp.toISOString()
257
- }))
258
- });
259
- }
260
-
261
- private _getHtmlForWebview(webview: vscode.Webview): string {
262
- return `<!DOCTYPE html>
263
- <html lang="en">
264
- <head>
265
- <meta charset="UTF-8">
266
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
267
- <title>CodeBakers Chat</title>
268
- <style>
269
- * {
270
- box-sizing: border-box;
271
- margin: 0;
272
- padding: 0;
273
- }
274
-
275
- body {
276
- font-family: var(--vscode-font-family);
277
- font-size: var(--vscode-font-size);
278
- color: var(--vscode-foreground);
279
- background: var(--vscode-editor-background);
280
- height: 100vh;
281
- display: flex;
282
- flex-direction: column;
283
- }
284
-
285
- .header {
286
- padding: 12px;
287
- border-bottom: 1px solid var(--vscode-panel-border);
288
- display: flex;
289
- align-items: center;
290
- gap: 8px;
291
- }
292
-
293
- .header-icon {
294
- font-size: 20px;
295
- }
296
-
297
- .header-title {
298
- font-weight: 600;
299
- flex: 1;
300
- }
301
-
302
- .clear-btn {
303
- background: transparent;
304
- border: none;
305
- color: var(--vscode-foreground);
306
- cursor: pointer;
307
- padding: 4px 8px;
308
- border-radius: 4px;
309
- }
310
-
311
- .clear-btn:hover {
312
- background: var(--vscode-toolbar-hoverBackground);
313
- }
314
-
315
- .messages {
316
- flex: 1;
317
- overflow-y: auto;
318
- padding: 12px;
319
- display: flex;
320
- flex-direction: column;
321
- gap: 12px;
322
- }
323
-
324
- .message {
325
- max-width: 90%;
326
- padding: 10px 14px;
327
- border-radius: 12px;
328
- line-height: 1.5;
329
- }
330
-
331
- .message.user {
332
- background: var(--vscode-button-background);
333
- color: var(--vscode-button-foreground);
334
- align-self: flex-end;
335
- border-bottom-right-radius: 4px;
336
- }
337
-
338
- .message.assistant {
339
- background: var(--vscode-editor-inactiveSelectionBackground);
340
- align-self: flex-start;
341
- border-bottom-left-radius: 4px;
342
- }
343
-
344
- .message pre {
345
- background: var(--vscode-textCodeBlock-background);
346
- padding: 8px;
347
- border-radius: 4px;
348
- overflow-x: auto;
349
- margin: 8px 0;
350
- }
351
-
352
- .message code {
353
- font-family: var(--vscode-editor-font-family);
354
- font-size: var(--vscode-editor-font-size);
355
- }
356
-
357
- .typing-indicator {
358
- display: none;
359
- align-self: flex-start;
360
- padding: 10px 14px;
361
- background: var(--vscode-editor-inactiveSelectionBackground);
362
- border-radius: 12px;
363
- }
364
-
365
- .typing-indicator.show {
366
- display: flex;
367
- gap: 4px;
368
- }
369
-
370
- .typing-dot {
371
- width: 8px;
372
- height: 8px;
373
- background: var(--vscode-foreground);
374
- border-radius: 50%;
375
- animation: typing 1.4s infinite ease-in-out;
376
- }
377
-
378
- .typing-dot:nth-child(2) { animation-delay: 0.2s; }
379
- .typing-dot:nth-child(3) { animation-delay: 0.4s; }
380
-
381
- @keyframes typing {
382
- 0%, 60%, 100% { transform: translateY(0); opacity: 0.3; }
383
- 30% { transform: translateY(-4px); opacity: 1; }
384
- }
385
-
386
- .input-area {
387
- padding: 12px;
388
- border-top: 1px solid var(--vscode-panel-border);
389
- display: flex;
390
- gap: 8px;
391
- }
392
-
393
- .input-area textarea {
394
- flex: 1;
395
- background: var(--vscode-input-background);
396
- color: var(--vscode-input-foreground);
397
- border: 1px solid var(--vscode-input-border);
398
- border-radius: 8px;
399
- padding: 10px 12px;
400
- font-family: inherit;
401
- font-size: inherit;
402
- resize: none;
403
- min-height: 40px;
404
- max-height: 120px;
405
- }
406
-
407
- .input-area textarea:focus {
408
- outline: none;
409
- border-color: var(--vscode-focusBorder);
410
- }
411
-
412
- .send-btn {
413
- background: var(--vscode-button-background);
414
- color: var(--vscode-button-foreground);
415
- border: none;
416
- border-radius: 8px;
417
- padding: 0 16px;
418
- cursor: pointer;
419
- font-weight: 500;
420
- }
421
-
422
- .send-btn:hover {
423
- background: var(--vscode-button-hoverBackground);
424
- }
425
-
426
- .send-btn:disabled {
427
- opacity: 0.5;
428
- cursor: not-allowed;
429
- }
430
-
431
- .footer {
432
- padding: 8px 12px;
433
- text-align: center;
434
- font-size: 11px;
435
- color: var(--vscode-descriptionForeground);
436
- border-top: 1px solid var(--vscode-panel-border);
437
- }
438
-
439
- .welcome {
440
- flex: 1;
441
- display: flex;
442
- flex-direction: column;
443
- align-items: center;
444
- justify-content: center;
445
- padding: 24px;
446
- text-align: center;
447
- }
448
-
449
- .welcome-icon {
450
- font-size: 48px;
451
- margin-bottom: 16px;
452
- }
453
-
454
- .welcome-title {
455
- font-size: 18px;
456
- font-weight: 600;
457
- margin-bottom: 8px;
458
- }
459
-
460
- .welcome-text {
461
- color: var(--vscode-descriptionForeground);
462
- margin-bottom: 24px;
463
- }
464
-
465
- .quick-actions {
466
- display: flex;
467
- flex-wrap: wrap;
468
- gap: 8px;
469
- justify-content: center;
470
- }
471
-
472
- .quick-action {
473
- background: var(--vscode-button-secondaryBackground);
474
- color: var(--vscode-button-secondaryForeground);
475
- border: none;
476
- border-radius: 16px;
477
- padding: 6px 14px;
478
- cursor: pointer;
479
- font-size: 12px;
480
- }
481
-
482
- .quick-action:hover {
483
- background: var(--vscode-button-secondaryHoverBackground);
484
- }
485
-
486
- .health-bar {
487
- padding: 6px 12px;
488
- border-bottom: 1px solid var(--vscode-panel-border);
489
- display: flex;
490
- align-items: center;
491
- gap: 8px;
492
- font-size: 11px;
493
- }
494
-
495
- .health-indicator {
496
- width: 8px;
497
- height: 8px;
498
- border-radius: 50%;
499
- background: #4caf50;
500
- }
501
-
502
- .health-indicator.warning { background: #ff9800; }
503
- .health-indicator.error { background: #f44336; }
504
-
505
- .health-text {
506
- flex: 1;
507
- color: var(--vscode-descriptionForeground);
508
- }
509
-
510
- .health-score {
511
- font-weight: 600;
512
- color: #4caf50;
513
- }
514
-
515
- .tools-bar {
516
- padding: 8px 12px;
517
- border-top: 1px solid var(--vscode-panel-border);
518
- display: flex;
519
- gap: 6px;
520
- flex-wrap: wrap;
521
- }
522
-
523
- .tool-chip {
524
- font-size: 10px;
525
- padding: 4px 8px;
526
- background: var(--vscode-button-secondaryBackground);
527
- color: var(--vscode-button-secondaryForeground);
528
- border: none;
529
- border-radius: 12px;
530
- cursor: pointer;
531
- }
532
-
533
- .tool-chip:hover {
534
- background: var(--vscode-button-secondaryHoverBackground);
535
- }
536
-
537
- .tool-chip.active {
538
- background: var(--vscode-button-background);
539
- color: var(--vscode-button-foreground);
540
- }
541
-
542
- .plan-badge {
543
- font-size: 10px;
544
- padding: 2px 8px;
545
- background: var(--vscode-button-background);
546
- color: var(--vscode-button-foreground);
547
- border-radius: 10px;
548
- }
549
-
550
- .plan-badge.trial {
551
- background: #f0a030;
552
- }
553
- </style>
554
- </head>
555
- <body>
556
- <div class="header">
557
- <span class="header-icon">🍪</span>
558
- <span class="header-title">CodeBakers</span>
559
- <span class="plan-badge" id="planBadge">Pro</span>
560
- <button class="clear-btn" onclick="clearChat()">Clear</button>
561
- </div>
562
-
563
- <div class="health-bar" id="healthBar">
564
- <div class="health-indicator" id="healthIndicator"></div>
565
- <span class="health-text">Project Health</span>
566
- <span class="health-score" id="healthScore">--</span>
567
- </div>
568
-
569
- <div class="messages" id="messages">
570
- <div class="welcome" id="welcome">
571
- <span class="welcome-icon">🍪</span>
572
- <div class="welcome-title">Welcome to CodeBakers</div>
573
- <div class="welcome-text">AI-powered coding with production-ready patterns</div>
574
- <div class="quick-actions">
575
- <button class="quick-action" onclick="quickAction('/build')">🔨 Build Project</button>
576
- <button class="quick-action" onclick="quickAction('/feature')">✨ Add Feature</button>
577
- <button class="quick-action" onclick="quickAction('/audit')">🔍 Audit Code</button>
578
- <button class="quick-action" onclick="runTool('guardian_status')">🛡️ Health Check</button>
579
- </div>
580
- </div>
581
-
582
- <div class="typing-indicator" id="typing">
583
- <div class="typing-dot"></div>
584
- <div class="typing-dot"></div>
585
- <div class="typing-dot"></div>
586
- </div>
587
- </div>
588
-
589
- <div class="tools-bar">
590
- <button class="tool-chip" onclick="runTool('guardian_status')">🛡️ Guardian</button>
591
- <button class="tool-chip" onclick="runTool('list_patterns')">📋 Patterns</button>
592
- <button class="tool-chip" onclick="runTool('run_tests')">🧪 Tests</button>
593
- <button class="tool-chip" onclick="runTool('run_audit')">🔍 Audit</button>
594
- <button class="tool-chip" onclick="runTool('ripple_check')">🌊 Ripple</button>
595
- </div>
596
-
597
- <div class="input-area">
598
- <textarea
599
- id="input"
600
- placeholder="Ask CodeBakers anything..."
601
- rows="1"
602
- onkeydown="handleKeydown(event)"
603
- oninput="autoResize(this)"
604
- ></textarea>
605
- <button class="send-btn" id="sendBtn" onclick="sendMessage()">Send</button>
606
- </div>
607
-
608
- <div class="footer">
609
- Powered by CodeBakers — a BotMakers Software
610
- </div>
611
-
612
- <script>
613
- const vscode = acquireVsCodeApi();
614
- const messagesEl = document.getElementById('messages');
615
- const welcomeEl = document.getElementById('welcome');
616
- const typingEl = document.getElementById('typing');
617
- const inputEl = document.getElementById('input');
618
- const sendBtn = document.getElementById('sendBtn');
619
-
620
- function sendMessage() {
621
- const message = inputEl.value.trim();
622
- if (!message) return;
623
-
624
- vscode.postMessage({ type: 'sendMessage', message });
625
- inputEl.value = '';
626
- inputEl.style.height = 'auto';
627
- sendBtn.disabled = true;
628
- }
629
-
630
- function quickAction(command) {
631
- inputEl.value = command + ' ';
632
- inputEl.focus();
633
- }
634
-
635
- function clearChat() {
636
- vscode.postMessage({ type: 'clearChat' });
637
- }
638
-
639
- function runTool(toolName) {
640
- vscode.postMessage({ type: 'runTool', tool: toolName });
641
- }
642
-
643
- function updateHealth(health, score) {
644
- const indicator = document.getElementById('healthIndicator');
645
- const scoreEl = document.getElementById('healthScore');
646
-
647
- scoreEl.textContent = score + '%';
648
-
649
- indicator.className = 'health-indicator';
650
- if (score < 50) {
651
- indicator.classList.add('error');
652
- scoreEl.style.color = '#f44336';
653
- } else if (score < 80) {
654
- indicator.classList.add('warning');
655
- scoreEl.style.color = '#ff9800';
656
- } else {
657
- scoreEl.style.color = '#4caf50';
658
- }
659
- }
660
-
661
- function updatePlan(plan) {
662
- const badge = document.getElementById('planBadge');
663
- badge.textContent = plan.charAt(0).toUpperCase() + plan.slice(1);
664
- badge.className = 'plan-badge';
665
- if (plan === 'trial') {
666
- badge.classList.add('trial');
667
- }
668
- }
669
-
670
- function handleKeydown(e) {
671
- if (e.key === 'Enter' && !e.shiftKey) {
672
- e.preventDefault();
673
- sendMessage();
674
- }
675
- }
676
-
677
- function autoResize(el) {
678
- el.style.height = 'auto';
679
- el.style.height = Math.min(el.scrollHeight, 120) + 'px';
680
- }
681
-
682
- function renderMessage(msg) {
683
- const div = document.createElement('div');
684
- div.className = 'message ' + msg.role;
685
- div.innerHTML = formatContent(msg.content);
686
- return div;
687
- }
688
-
689
- function formatContent(content) {
690
- // Simple markdown-like formatting
691
- return content
692
- .replace(/\`\`\`(\\w*)\\n([\\s\\S]*?)\`\`\`/g, '<pre><code>$2</code></pre>')
693
- .replace(/\`([^\`]+)\`/g, '<code>$1</code>')
694
- .replace(/\\n/g, '<br>');
695
- }
696
-
697
- window.addEventListener('message', event => {
698
- const data = event.data;
699
-
700
- switch (data.type) {
701
- case 'updateMessages':
702
- // Hide welcome, show messages
703
- if (data.messages.length > 0) {
704
- welcomeEl.style.display = 'none';
705
- } else {
706
- welcomeEl.style.display = 'flex';
707
- }
708
-
709
- // Clear and re-render messages
710
- const existing = messagesEl.querySelectorAll('.message');
711
- existing.forEach(el => el.remove());
712
-
713
- data.messages.forEach(msg => {
714
- messagesEl.insertBefore(renderMessage(msg), typingEl);
715
- });
716
-
717
- // Scroll to bottom
718
- messagesEl.scrollTop = messagesEl.scrollHeight;
719
- sendBtn.disabled = false;
720
- break;
721
-
722
- case 'typing':
723
- typingEl.classList.toggle('show', data.isTyping);
724
- messagesEl.scrollTop = messagesEl.scrollHeight;
725
- break;
726
-
727
- case 'updateHealth':
728
- updateHealth(data.health, data.score);
729
- break;
730
-
731
- case 'updatePlan':
732
- updatePlan(data.plan);
733
- break;
734
-
735
- case 'toolResult':
736
- // Show tool result as a message
737
- const resultDiv = document.createElement('div');
738
- resultDiv.className = 'message assistant';
739
- resultDiv.innerHTML = '<strong>🔧 ' + data.tool + '</strong><br>' + formatContent(JSON.stringify(data.result, null, 2));
740
- messagesEl.insertBefore(resultDiv, typingEl);
741
- messagesEl.scrollTop = messagesEl.scrollHeight;
742
- break;
743
- }
744
- });
745
- </script>
746
- </body>
747
- </html>`;
748
- }
749
- }