@keak/sdk 1.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 (89) hide show
  1. package/README.md +131 -0
  2. package/dist/Conversion.d.ts +13 -0
  3. package/dist/Conversion.d.ts.map +1 -0
  4. package/dist/KeakToolbarShadow.d.ts +21 -0
  5. package/dist/KeakToolbarShadow.d.ts.map +1 -0
  6. package/dist/components/ui/card.d.ts +9 -0
  7. package/dist/components/ui/card.d.ts.map +1 -0
  8. package/dist/components/ui/html-preview.d.ts +9 -0
  9. package/dist/components/ui/html-preview.d.ts.map +1 -0
  10. package/dist/components/ui/simple-tabs.d.ts +26 -0
  11. package/dist/components/ui/simple-tabs.d.ts.map +1 -0
  12. package/dist/components/ui/spinner.d.ts +6 -0
  13. package/dist/components/ui/spinner.d.ts.map +1 -0
  14. package/dist/components/ui/tabs.d.ts +13 -0
  15. package/dist/components/ui/tabs.d.ts.map +1 -0
  16. package/dist/components/ui/textarea.d.ts +6 -0
  17. package/dist/components/ui/textarea.d.ts.map +1 -0
  18. package/dist/index.cjs.js +17407 -0
  19. package/dist/index.cjs.js.map +1 -0
  20. package/dist/index.d.ts +101 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +17395 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/runtime/sourceInjector.d.ts +2 -0
  25. package/dist/runtime/sourceInjector.d.ts.map +1 -0
  26. package/dist/scripts/sourcePathInjection.d.ts +11 -0
  27. package/dist/scripts/sourcePathInjection.d.ts.map +1 -0
  28. package/dist/services/index.d.ts +7 -0
  29. package/dist/services/index.d.ts.map +1 -0
  30. package/dist/services/telemetry/index.d.ts +20 -0
  31. package/dist/services/telemetry/index.d.ts.map +1 -0
  32. package/dist/services/telemetry/telemetryService.d.ts +66 -0
  33. package/dist/services/telemetry/telemetryService.d.ts.map +1 -0
  34. package/dist/services/telemetry/types.d.ts +64 -0
  35. package/dist/services/telemetry/types.d.ts.map +1 -0
  36. package/dist/toolbar/AIPromptPanel.d.ts +9 -0
  37. package/dist/toolbar/AIPromptPanel.d.ts.map +1 -0
  38. package/dist/toolbar/ElementSelector.d.ts +8 -0
  39. package/dist/toolbar/ElementSelector.d.ts.map +1 -0
  40. package/dist/toolbar/ExperimentPanel.d.ts +9 -0
  41. package/dist/toolbar/ExperimentPanel.d.ts.map +1 -0
  42. package/dist/toolbar/KeakToolbar.d.ts +10 -0
  43. package/dist/toolbar/KeakToolbar.d.ts.map +1 -0
  44. package/dist/toolbar/MetricsPanel.d.ts +7 -0
  45. package/dist/toolbar/MetricsPanel.d.ts.map +1 -0
  46. package/dist/toolbar/PageScanPanel.d.ts +15 -0
  47. package/dist/toolbar/PageScanPanel.d.ts.map +1 -0
  48. package/dist/toolbar/components/PrimaryButton.d.ts +12 -0
  49. package/dist/toolbar/components/PrimaryButton.d.ts.map +1 -0
  50. package/dist/toolbar/components/WarningButton.d.ts +12 -0
  51. package/dist/toolbar/components/WarningButton.d.ts.map +1 -0
  52. package/dist/toolbar/components/icons/index.d.ts +13 -0
  53. package/dist/toolbar/components/icons/index.d.ts.map +1 -0
  54. package/dist/toolbar/components/ui/Badge.d.ts +10 -0
  55. package/dist/toolbar/components/ui/Badge.d.ts.map +1 -0
  56. package/dist/toolbar/components/ui/Button.d.ts +12 -0
  57. package/dist/toolbar/components/ui/Button.d.ts.map +1 -0
  58. package/dist/toolbar/components/ui/Progress.d.ts +5 -0
  59. package/dist/toolbar/components/ui/Progress.d.ts.map +1 -0
  60. package/dist/toolbar/components/ui/Tabs.d.ts +44 -0
  61. package/dist/toolbar/components/ui/Tabs.d.ts.map +1 -0
  62. package/dist/toolbar/components/ui/dropdown-menu.d.ts +28 -0
  63. package/dist/toolbar/components/ui/dropdown-menu.d.ts.map +1 -0
  64. package/dist/toolbar/lib/utils.d.ts +3 -0
  65. package/dist/toolbar/lib/utils.d.ts.map +1 -0
  66. package/dist/toolbar/utils/fiberSource.d.ts +64 -0
  67. package/dist/toolbar/utils/fiberSource.d.ts.map +1 -0
  68. package/dist/toolbar/utils/keakCodeClient.d.ts +104 -0
  69. package/dist/toolbar/utils/keakCodeClient.d.ts.map +1 -0
  70. package/dist/toolbar.css +1 -0
  71. package/dist/toolbar.js +1257 -0
  72. package/dist/toolbar.js.map +1 -0
  73. package/dist/utils/generateElementId.d.ts +44 -0
  74. package/dist/utils/generateElementId.d.ts.map +1 -0
  75. package/dist/utils/injectDataId.d.ts +33 -0
  76. package/dist/utils/injectDataId.d.ts.map +1 -0
  77. package/package.json +152 -0
  78. package/src/cli/ai-helper.js +206 -0
  79. package/src/cli/code-transformer.js +354 -0
  80. package/src/cli/conversion-detector.js +716 -0
  81. package/src/cli/framework-config.js +477 -0
  82. package/src/cli/install.js +618 -0
  83. package/src/cli/keak-setup.js +43 -0
  84. package/src/cli/revert-conversions.js +264 -0
  85. package/src/cli/safe-transformer.js +456 -0
  86. package/src/cli/simple-transformer.js +339 -0
  87. package/src/plugins/README.md +131 -0
  88. package/src/plugins/babel-source-inject.cjs +170 -0
  89. package/src/plugins/next.cjs +145 -0
@@ -0,0 +1,618 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { execSync } from 'child_process';
6
+ import { AIHelper, LocalAIHelper } from './ai-helper.js';
7
+ import ConversionDetector from './conversion-detector.js';
8
+ import { FrameworkConfigManager } from './framework-config.js';
9
+
10
+ // ANSI color codes for terminal output
11
+ const colors = {
12
+ reset: '\x1b[0m',
13
+ bright: '\x1b[1m',
14
+ green: '\x1b[32m',
15
+ yellow: '\x1b[33m',
16
+ blue: '\x1b[34m',
17
+ cyan: '\x1b[36m',
18
+ red: '\x1b[31m',
19
+ };
20
+
21
+ // Check for command-line arguments
22
+ const args = process.argv.slice(2);
23
+ const command = args[0];
24
+
25
+ // Handle conversions command
26
+ if (command === 'conversions') {
27
+ console.log(`
28
+ ${colors.cyan}${colors.bright}
29
+ ╔═══════════════════════════════════════╗
30
+ ║ ║
31
+ ║ 🎯 Keak Conversion Tracking Setup ║
32
+ ║ ║
33
+ ╚═══════════════════════════════════════╝
34
+ ${colors.reset}
35
+ `);
36
+
37
+ const detector = new ConversionDetector();
38
+ const targetDir = args[1] || process.cwd();
39
+
40
+ console.log(`${colors.blue}🎯 Setting up conversion tracking...${colors.reset}\n`);
41
+
42
+ const result = detector.createConversionFiles(targetDir);
43
+
44
+ if (result.success) {
45
+ const report = result.report;
46
+
47
+ console.log(`${colors.green}✅ Conversion tracking setup complete!${colors.reset}`);
48
+ console.log(`${colors.cyan}🌐 Results page: ${result.htmlPath}${colors.reset}`);
49
+ console.log(`
50
+ ${colors.blue}📊 Results:${colors.reset}
51
+ • Files processed: ${report.stats.filesProcessed}
52
+ • Files modified: ${report.stats.filesModified}
53
+ • Elements wrapped: ${report.stats.elementsWrapped}
54
+ `);
55
+
56
+ if (result.errors && result.errors.length > 0) {
57
+ console.log(`${colors.yellow}⚠️ ${result.errors.length} files had issues - check the results page for details${colors.reset}`);
58
+ }
59
+
60
+ console.log(`
61
+ ${colors.yellow}🔧 What happened:${colors.reset}
62
+ 1. All React files were scanned automatically
63
+ 2. Clickable elements (buttons, links, etc.) were wrapped with components
64
+ 3. Backup files (.keak-backup) were created for all changes
65
+ 4. Your components now automatically track conversion events
66
+
67
+ ${colors.green}🚀 Your conversion tracking is now active!${colors.reset}
68
+ `);
69
+ } else {
70
+ console.error(`${colors.red}❌ Failed to setup conversion tracking: ${result.error}${colors.reset}`);
71
+ process.exit(1);
72
+ }
73
+
74
+ process.exit(0);
75
+ }
76
+
77
+ console.log(`
78
+ ${colors.cyan}${colors.bright}
79
+ ╔═══════════════════════════════════════╗
80
+ ║ ║
81
+ ║ 🚀 Keak SDK Auto-Setup Wizard ║
82
+ ║ ║
83
+ ╚═══════════════════════════════════════╝
84
+ ${colors.reset}
85
+ `);
86
+
87
+ class KeakInstaller {
88
+ constructor() {
89
+ this.projectRoot = process.cwd();
90
+ this.framework = null;
91
+ this.entryFile = null;
92
+ this.aiApiKey = process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
93
+ }
94
+
95
+ async run() {
96
+ try {
97
+ console.log(`${colors.blue}🔍 Detecting project setup...${colors.reset}\n`);
98
+
99
+ // Step 1: Detect framework
100
+ this.detectFramework();
101
+
102
+ // Step 2: Find entry file
103
+ this.findEntryFile();
104
+
105
+ // Step 3: Setup framework configuration (Babel, etc.)
106
+ console.log(`\n${colors.blue}🔧 Configuring build tools for optimal Keak performance...${colors.reset}\n`);
107
+ const configManager = new FrameworkConfigManager(this.projectRoot);
108
+ const configSuccess = await configManager.setupBabelConfig();
109
+
110
+ if (configSuccess) {
111
+ console.log(`${colors.green}✅ Build configuration complete${colors.reset}\n`);
112
+ } else {
113
+ console.log(`${colors.yellow}⚠️ Build configuration incomplete - Keak may have limited functionality${colors.reset}\n`);
114
+ }
115
+
116
+ // Step 4: Check if already installed
117
+ if (this.isAlreadyInstalled()) {
118
+ console.log(`${colors.green}✅ Keak is already installed!${colors.reset}`);
119
+ this.showUsageInstructions();
120
+ return;
121
+ }
122
+
123
+ // Step 5: Attempt automatic installation
124
+ const installed = await this.autoInstall();
125
+
126
+ if (installed) {
127
+ console.log(`\n${colors.green}${colors.bright}✨ Success! Keak has been installed.${colors.reset}`);
128
+ this.showPostInstallInstructions();
129
+ } else {
130
+ // Step 6: Use AI for complex cases
131
+ await this.aiAssistedInstall();
132
+ }
133
+
134
+ } catch (error) {
135
+ console.error(`${colors.red}❌ Installation failed: ${error.message}${colors.reset}`);
136
+ this.showManualInstructions();
137
+ }
138
+ }
139
+
140
+ detectFramework() {
141
+ const packageJsonPath = path.join(this.projectRoot, 'package.json');
142
+
143
+ if (!fs.existsSync(packageJsonPath)) {
144
+ throw new Error('No package.json found. Are you in a Node.js project?');
145
+ }
146
+
147
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
148
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
149
+
150
+ if (deps['next']) {
151
+ this.framework = 'nextjs';
152
+ console.log(`${colors.green}✓${colors.reset} Detected: Next.js`);
153
+ } else if (deps['react-scripts']) {
154
+ this.framework = 'create-react-app';
155
+ console.log(`${colors.green}✓${colors.reset} Detected: Create React App`);
156
+ } else if (deps['vite'] && deps['react']) {
157
+ this.framework = 'vite-react';
158
+ console.log(`${colors.green}✓${colors.reset} Detected: Vite + React`);
159
+ } else if (deps['gatsby']) {
160
+ this.framework = 'gatsby';
161
+ console.log(`${colors.green}✓${colors.reset} Detected: Gatsby`);
162
+ } else if (deps['react']) {
163
+ this.framework = 'react';
164
+ console.log(`${colors.green}✓${colors.reset} Detected: React (custom setup)`);
165
+ } else {
166
+ throw new Error('Could not detect React in your project. Keak currently supports React applications.');
167
+ }
168
+ }
169
+
170
+ findEntryFile() {
171
+ const possibleEntries = {
172
+ 'nextjs': [
173
+ 'app/layout.tsx',
174
+ 'app/layout.jsx',
175
+ 'app/layout.js',
176
+ 'pages/_app.tsx',
177
+ 'pages/_app.jsx',
178
+ 'pages/_app.js',
179
+ ],
180
+ 'create-react-app': [
181
+ 'src/index.tsx',
182
+ 'src/index.jsx',
183
+ 'src/index.js',
184
+ 'src/App.tsx',
185
+ 'src/App.jsx',
186
+ 'src/App.js',
187
+ ],
188
+ 'vite-react': [
189
+ 'src/main.tsx',
190
+ 'src/main.jsx',
191
+ 'src/App.tsx',
192
+ 'src/App.jsx',
193
+ ],
194
+ 'gatsby': [
195
+ 'src/pages/_app.tsx',
196
+ 'src/pages/_app.js',
197
+ 'gatsby-browser.js',
198
+ ],
199
+ 'react': [
200
+ 'src/index.tsx',
201
+ 'src/index.jsx',
202
+ 'src/index.js',
203
+ 'index.tsx',
204
+ 'index.jsx',
205
+ 'index.js',
206
+ 'src/App.tsx',
207
+ 'src/App.jsx',
208
+ 'src/App.js',
209
+ 'App.tsx',
210
+ 'App.jsx',
211
+ 'App.js',
212
+ ]
213
+ };
214
+
215
+ const entries = possibleEntries[this.framework] || possibleEntries.react;
216
+
217
+ for (const entry of entries) {
218
+ const fullPath = path.join(this.projectRoot, entry);
219
+ if (fs.existsSync(fullPath)) {
220
+ this.entryFile = fullPath;
221
+ console.log(`${colors.green}✓${colors.reset} Found entry file: ${entry}`);
222
+ return;
223
+ }
224
+ }
225
+
226
+ // If no entry file found, try to find any file with ReactDOM.render or createRoot
227
+ this.entryFile = this.findReactDOMRenderFile();
228
+
229
+ if (!this.entryFile) {
230
+ throw new Error('Could not find React entry file. Please specify manually.');
231
+ }
232
+ }
233
+
234
+ findReactDOMRenderFile() {
235
+ const searchDirs = ['src', '.'];
236
+
237
+ for (const dir of searchDirs) {
238
+ const fullDir = path.join(this.projectRoot, dir);
239
+ if (!fs.existsSync(fullDir)) continue;
240
+
241
+ const files = this.getAllFiles(fullDir, ['.js', '.jsx', '.ts', '.tsx']);
242
+
243
+ for (const file of files) {
244
+ const content = fs.readFileSync(file, 'utf-8');
245
+ if (content.includes('ReactDOM.render') ||
246
+ content.includes('ReactDOM.createRoot') ||
247
+ content.includes('createRoot(')) {
248
+ console.log(`${colors.green}✓${colors.reset} Found React render in: ${path.relative(this.projectRoot, file)}`);
249
+ return file;
250
+ }
251
+ }
252
+ }
253
+
254
+ return null;
255
+ }
256
+
257
+ getAllFiles(dir, extensions) {
258
+ const files = [];
259
+
260
+ const items = fs.readdirSync(dir);
261
+ for (const item of items) {
262
+ const fullPath = path.join(dir, item);
263
+
264
+ // Skip node_modules and other common directories
265
+ if (item === 'node_modules' || item === '.git' || item === 'dist' || item === 'build') {
266
+ continue;
267
+ }
268
+
269
+ const stat = fs.statSync(fullPath);
270
+ if (stat.isDirectory()) {
271
+ files.push(...this.getAllFiles(fullPath, extensions));
272
+ } else if (extensions.some(ext =item.endsWith(ext))) {
273
+ files.push(fullPath);
274
+ }
275
+ }
276
+
277
+ return files;
278
+ }
279
+
280
+ isAlreadyInstalled() {
281
+ if (!this.entryFile) return false;
282
+
283
+ const content = fs.readFileSync(this.entryFile, 'utf-8');
284
+ return content.includes('KeakProvider') || content.includes('keak-sdk');
285
+ }
286
+
287
+ async autoInstall() {
288
+ console.log(`\n${colors.blue}🔧 Attempting automatic installation...${colors.reset}\n`);
289
+
290
+ const content = fs.readFileSync(this.entryFile, 'utf-8');
291
+ let modified = content;
292
+
293
+ try {
294
+ if (this.framework === 'nextjs') {
295
+ modified = this.wrapNextJs(content);
296
+ } else if (this.framework === 'create-react-app' || this.framework === 'vite-react') {
297
+ modified = this.wrapCRA(content);
298
+ } else {
299
+ modified = this.wrapGenericReact(content);
300
+ }
301
+
302
+ if (modified !== content) {
303
+ // Create backup
304
+ const backupPath = `${this.entryFile}.backup`;
305
+ fs.writeFileSync(backupPath, content);
306
+ console.log(`${colors.cyan}📋 Created backup: ${path.basename(backupPath)}${colors.reset}`);
307
+
308
+ // Write modified file
309
+ fs.writeFileSync(this.entryFile, modified);
310
+ console.log(`${colors.green}✓${colors.reset} Modified: ${path.relative(this.projectRoot, this.entryFile)}`);
311
+
312
+ return true;
313
+ }
314
+ } catch (error) {
315
+ console.log(`${colors.yellow}⚠️ Auto-installation needs help with your setup${colors.reset}`);
316
+ }
317
+
318
+ return false;
319
+ }
320
+
321
+ wrapNextJs(content) {
322
+ const isAppDir = this.entryFile.includes('app/layout');
323
+
324
+ if (isAppDir) {
325
+ // Next.js 13+ App Directory
326
+ if (!content.includes('KeakProvider')) {
327
+ // Add import - include both KeakProvider and KeakToolbar
328
+ const importLine = "import { KeakProvider, KeakToolbar } from 'keak-sdk';\n";
329
+ let modified = content;
330
+
331
+ // Add import after existing imports
332
+ const lastImportIndex = modified.lastIndexOf('import ');
333
+ if (lastImportIndex !== -1) {
334
+ const endOfLine = modified.indexOf('\n', lastImportIndex);
335
+ modified = modified.slice(0, endOfLine + 1) + importLine + modified.slice(endOfLine + 1);
336
+ } else {
337
+ modified = importLine + modified;
338
+ }
339
+
340
+ // Wrap children in body with KeakProvider and add KeakToolbar
341
+ const bodyMatch = modified.match(/(<body[^>]*>)([\s\S]*?)(<\/body>)/);
342
+ if (bodyMatch) {
343
+ const bodyContent = bodyMatch[2].trim();
344
+ const wrapped = `${bodyMatch[1]}
345
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
346
+ ${bodyContent}
347
+ <KeakToolbar />
348
+ </KeakProvider>
349
+ ${bodyMatch[3]}`;
350
+ modified = modified.replace(bodyMatch[0], wrapped);
351
+ }
352
+
353
+ return modified;
354
+ }
355
+ } else {
356
+ // Next.js Pages Directory
357
+ if (!content.includes('KeakProvider')) {
358
+ // Add import - include both KeakProvider and KeakToolbar
359
+ const importLine = "import { KeakProvider, KeakToolbar } from 'keak-sdk';\n";
360
+ let modified = content;
361
+
362
+ const lastImportIndex = modified.lastIndexOf('import ');
363
+ if (lastImportIndex !== -1) {
364
+ const endOfLine = modified.indexOf('\n', lastImportIndex);
365
+ modified = modified.slice(0, endOfLine + 1) + importLine + modified.slice(endOfLine + 1);
366
+ } else {
367
+ modified = importLine + modified;
368
+ }
369
+
370
+ // Wrap Component with KeakProvider and add KeakToolbar
371
+ const componentMatch = modified.match(/(return\s*\(?\s*)([\s\S]*?)(\s*\)?;?\s*})/);
372
+ if (componentMatch) {
373
+ const wrapped = `${componentMatch[1]}
374
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
375
+ ${componentMatch[2]}
376
+ <KeakToolbar />
377
+ </KeakProvider>
378
+ ${componentMatch[3]}`;
379
+ modified = modified.replace(componentMatch[0], wrapped);
380
+ }
381
+
382
+ return modified;
383
+ }
384
+ }
385
+
386
+ return content;
387
+ }
388
+
389
+ wrapCRA(content) {
390
+ let modified = content;
391
+
392
+ // Add import - include both KeakProvider and KeakToolbar
393
+ if (!content.includes('KeakProvider')) {
394
+ const importLine = "import { KeakProvider, KeakToolbar } from 'keak-sdk';\n";
395
+
396
+ const lastImportIndex = modified.lastIndexOf('import ');
397
+ if (lastImportIndex !== -1) {
398
+ const endOfLine = modified.indexOf('\n', lastImportIndex);
399
+ modified = modified.slice(0, endOfLine + 1) + importLine + modified.slice(endOfLine + 1);
400
+ } else {
401
+ modified = importLine + modified;
402
+ }
403
+ }
404
+
405
+ // Find ReactDOM.render or createRoot
406
+ if (content.includes('ReactDOM.render')) {
407
+ // Old React 17 style
408
+ const renderMatch = modified.match(/(ReactDOM\.render\s*\(\s*)([\s\S]*?)(\s*,\s*document\.getElementById)/);
409
+ if (renderMatch) {
410
+ const wrapped = `${renderMatch[1]}
411
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
412
+ ${renderMatch[2]}
413
+ <KeakToolbar />
414
+ </KeakProvider>
415
+ ${renderMatch[3]}`;
416
+ modified = modified.replace(renderMatch[0], wrapped);
417
+ }
418
+ } else if (content.includes('createRoot')) {
419
+ // React 18 style
420
+ const renderMatch = modified.match(/(root\.render\s*\(\s*)([\s\S]*?)(\s*\))/);
421
+ if (renderMatch) {
422
+ const wrapped = `${renderMatch[1]}
423
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
424
+ ${renderMatch[2]}
425
+ <KeakToolbar />
426
+ </KeakProvider>
427
+ ${renderMatch[3]}`;
428
+ modified = modified.replace(renderMatch[0], wrapped);
429
+ }
430
+ }
431
+
432
+ return modified;
433
+ }
434
+
435
+ wrapGenericReact(content) {
436
+ // Generic React app wrapper
437
+ return this.wrapCRA(content);
438
+ }
439
+
440
+ async aiAssistedInstall() {
441
+ console.log(`\n${colors.cyan}🤖 Using AI to help with installation...${colors.reset}\n`);
442
+
443
+ const content = fs.readFileSync(this.entryFile, 'utf-8');
444
+ const aiHelper = new AIHelper();
445
+ const localHelper = new LocalAIHelper();
446
+
447
+ try {
448
+ // First try the Keak AI service (free, no API key needed)
449
+ console.log(`${colors.blue}Connecting to Keak AI service...${colors.reset}`);
450
+ const modifiedContent = await Promise.race([
451
+ aiHelper.getInstallationHelp(content, this.entryFile, this.framework),
452
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000))
453
+ ]);
454
+
455
+ if (modifiedContent && modifiedContent !== content) {
456
+ // Create backup
457
+ const backupPath = `${this.entryFile}.backup`;
458
+ fs.writeFileSync(backupPath, content);
459
+ console.log(`${colors.cyan}📋 Created backup: ${path.basename(backupPath)}${colors.reset}`);
460
+
461
+ // Write modified file
462
+ fs.writeFileSync(this.entryFile, modifiedContent);
463
+ console.log(`${colors.green}✓${colors.reset} AI successfully updated: ${path.relative(this.projectRoot, this.entryFile)}`);
464
+
465
+ console.log(`\n${colors.green}${colors.bright}✨ Success! Keak has been installed with AI assistance.${colors.reset}`);
466
+ this.showPostInstallInstructions();
467
+ return;
468
+ }
469
+ } catch (error) {
470
+ console.log(`${colors.yellow}Online AI unavailable, using local intelligence...${colors.reset}`);
471
+ }
472
+
473
+ // Fallback to local AI helper
474
+ try {
475
+ const isTypeScript = this.entryFile.endsWith('.ts') || this.entryFile.endsWith('.tsx');
476
+ const modifiedContent = localHelper.addKeakProvider(content, isTypeScript);
477
+
478
+ if (modifiedContent && modifiedContent !== content) {
479
+ // Create backup
480
+ const backupPath = `${this.entryFile}.backup`;
481
+ fs.writeFileSync(backupPath, content);
482
+ console.log(`${colors.cyan}📋 Created backup: ${path.basename(backupPath)}${colors.reset}`);
483
+
484
+ // Write modified file
485
+ fs.writeFileSync(this.entryFile, modifiedContent);
486
+ console.log(`${colors.green}✓${colors.reset} Successfully updated: ${path.relative(this.projectRoot, this.entryFile)}`);
487
+
488
+ console.log(`\n${colors.green}${colors.bright}✨ Success! Keak has been installed.${colors.reset}`);
489
+ this.showPostInstallInstructions();
490
+ return;
491
+ }
492
+ } catch (error) {
493
+ console.log(`${colors.yellow}Automated installation needs manual help.${colors.reset}`);
494
+ }
495
+
496
+ // If all else fails, show manual instructions
497
+ this.showManualInstructions();
498
+ }
499
+
500
+ showManualInstructions() {
501
+ const relativeEntry = this.entryFile
502
+ ? path.relative(this.projectRoot, this.entryFile)
503
+ : 'your entry file (e.g., src/index.tsx or src/App.tsx)';
504
+
505
+ console.log(`
506
+ ${colors.yellow}📝 Manual Installation Required${colors.reset}
507
+
508
+ Please add Keak to your app manually:
509
+
510
+ 1. Open ${colors.cyan}${relativeEntry}${colors.reset}
511
+
512
+ 2. Add this import at the top:
513
+ ${colors.green}import { KeakProvider } from 'keak-sdk';${colors.reset}
514
+
515
+ 3. Wrap your main component:
516
+ ${colors.green}<KeakProvider config={{ apiKey: 'demo', debug: true }}><YourApp /></KeakProvider>${colors.reset}
517
+
518
+ Example for ${this.framework}:
519
+ ${this.getFrameworkExample()}
520
+ `);
521
+ }
522
+
523
+ getFrameworkExample() {
524
+ const examples = {
525
+ 'nextjs': `
526
+ // app/layout.tsx
527
+ import { KeakProvider } from 'keak-sdk';
528
+
529
+ export default function RootLayout({ children }) {
530
+ return (
531
+ <html><body>
532
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
533
+ {children}
534
+ </KeakProvider>
535
+ </body></html>);
536
+ }`,
537
+ 'create-react-app': `
538
+ // src/index.js
539
+ import { KeakProvider } from 'keak-sdk';
540
+
541
+ root.render(
542
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
543
+ <App />
544
+ </KeakProvider>
545
+ );`,
546
+ 'vite-react': `
547
+ // src/main.tsx
548
+ import { KeakProvider } from 'keak-sdk';
549
+
550
+ ReactDOM.createRoot(document.getElementById('root')).render(
551
+ <KeakProvider config={{ apiKey: 'demo', debug: true }}>
552
+ <App />
553
+ </KeakProvider>
554
+ );`
555
+ };
556
+
557
+ return examples[this.framework] || examples['create-react-app'];
558
+ }
559
+
560
+ showPostInstallInstructions() {
561
+ console.log(`
562
+ ${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
563
+
564
+ ${colors.green}🎉 Keak is ready to use!${colors.reset}
565
+
566
+ Start your development server and look for the ${colors.bright}Keak toolbar${colors.reset}
567
+ in the ${colors.bright}bottom-right corner${colors.reset} of your app.
568
+
569
+ ${colors.blue}Quick Tips:${colors.reset}
570
+ • Click the toolbar to expand it
571
+ • Use "Select" to pick elements for testing
572
+ • Try the AI prompts for optimization ideas
573
+ • Press ${colors.bright}Cmd+Shift+K${colors.reset} to toggle the toolbar
574
+
575
+ ${colors.blue}🔧 Important for Next.js users:${colors.reset}
576
+ • Keak requires Babel for source mapping
577
+ • We've disabled Turbopack in your dev script
578
+ • Use ${colors.bright}npm run dev:turbo${colors.reset} if you need Turbopack
579
+ • ${colors.yellow}Restart your dev server${colors.reset} for changes to take effect
580
+
581
+ ${colors.blue}🎯 Want conversion tracking?${colors.reset}
582
+ Run: ${colors.bright}npx keak-setup conversions${colors.reset}
583
+
584
+ ${colors.yellow}Need help?${colors.reset} Visit https://docs.keak.dev
585
+
586
+ ${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
587
+ `);
588
+ }
589
+
590
+ showUsageInstructions() {
591
+ console.log(`
592
+ The Keak toolbar should appear in your app when running in development mode.
593
+
594
+ If you don't see it, make sure:
595
+ 1. Your app is running in development mode
596
+ 2. You've restarted your dev server after installation
597
+
598
+ Press ${colors.bright}Cmd+Shift+K${colors.reset} in your app to toggle the toolbar.
599
+ `);
600
+ }
601
+ }
602
+
603
+ // Run the installer
604
+ const installer = new KeakInstaller();
605
+
606
+ // Gracefully handle errors during postinstall (don't fail the install)
607
+ installer.run().catch((error) => {
608
+ // Only show error in verbose mode or when run explicitly (not postinstall)
609
+ const isPostInstall = process.env.npm_lifecycle_event === 'postinstall';
610
+
611
+ if (!isPostInstall) {
612
+ console.error(`${colors.red}Installation failed: ${error.message}${colors.reset}`);
613
+ process.exit(1);
614
+ } else {
615
+ // Silent fail for postinstall - don't block package installation
616
+ console.log(`${colors.yellow}ℹ️ Keak auto-setup skipped. Run 'npx keak-setup' manually when ready.${colors.reset}`);
617
+ }
618
+ });
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Main entry point for keak-setup commands
4
+ const args = process.argv.slice(2);
5
+ const command = args[0];
6
+
7
+ if (!command) {
8
+ console.log(`
9
+ 🚀 Keak Setup Commands
10
+
11
+ Usage: npx keak-setup <command>
12
+
13
+ Commands:
14
+ install Set up Keak SDK in your React app
15
+ conversions Set up automatic conversion tracking
16
+ revert-conversions Undo conversion tracking changes
17
+
18
+ Examples:
19
+ npx keak-setup install
20
+ npx keak-setup conversions
21
+ npx keak-setup revert-conversions
22
+
23
+ For more help: https://docs.keak.dev
24
+ `);
25
+ process.exit(0);
26
+ }
27
+
28
+ // Route to appropriate script
29
+ (async () => {
30
+ if (command === 'install') {
31
+ await import('./install.js');
32
+ } else if (command === 'conversions') {
33
+ // Run conversions setup directly
34
+ await import('./install.js');
35
+ } else if (command === 'revert-conversions') {
36
+ // Run revert command
37
+ await import('./revert-conversions.js');
38
+ } else {
39
+ console.error(`Unknown command: ${command}`);
40
+ console.log('Available commands: install, conversions, revert-conversions');
41
+ process.exit(1);
42
+ }
43
+ })();