humanbehavior-js 0.4.14 → 0.4.16

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.
@@ -16,6 +16,16 @@ export interface FrameworkInfo {
16
16
  hasTypeScript?: boolean;
17
17
  hasRouter?: boolean;
18
18
  projectRoot?: string;
19
+ version?: string;
20
+ majorVersion?: number;
21
+ features?: {
22
+ hasReact18?: boolean;
23
+ hasVue3?: boolean;
24
+ hasNuxt3?: boolean;
25
+ hasAngularStandalone?: boolean;
26
+ hasNextAppRouter?: boolean;
27
+ hasSvelteKit?: boolean;
28
+ };
19
29
  }
20
30
 
21
31
  export interface CodeModification {
@@ -43,6 +53,30 @@ export class AutoInstallationWizard {
43
53
  this.projectRoot = projectRoot;
44
54
  }
45
55
 
56
+ /**
57
+ * Simple version comparison utility
58
+ */
59
+ private compareVersions(version1: string, version2: string): number {
60
+ const v1Parts = version1.split('.').map(Number);
61
+ const v2Parts = version2.split('.').map(Number);
62
+
63
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
64
+ const v1 = v1Parts[i] || 0;
65
+ const v2 = v2Parts[i] || 0;
66
+ if (v1 > v2) return 1;
67
+ if (v1 < v2) return -1;
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ private isVersionGte(version: string, target: string): boolean {
73
+ return this.compareVersions(version, target) >= 0;
74
+ }
75
+
76
+ private getMajorVersion(version: string): number {
77
+ return parseInt(version.split('.')[0]) || 0;
78
+ }
79
+
46
80
  /**
47
81
  * Main installation method - detects framework and auto-installs
48
82
  */
@@ -99,84 +133,145 @@ export class AutoInstallationWizard {
99
133
  ...packageJson.devDependencies
100
134
  };
101
135
 
102
- // Detect framework
136
+ // Detect framework with version information
103
137
  let framework: FrameworkInfo = {
104
138
  name: 'vanilla',
105
139
  type: 'vanilla',
106
- projectRoot: this.projectRoot
140
+ projectRoot: this.projectRoot,
141
+ features: {}
107
142
  };
108
143
 
109
144
  if (dependencies.nuxt) {
145
+ const nuxtVersion = dependencies.nuxt;
146
+ const isNuxt3 = this.isVersionGte(nuxtVersion, '3.0.0');
147
+
110
148
  framework = {
111
149
  name: 'nuxt',
112
150
  type: 'nuxt',
151
+ version: nuxtVersion,
152
+ majorVersion: this.getMajorVersion(nuxtVersion),
113
153
  hasTypeScript: !!dependencies.typescript,
114
154
  hasRouter: true,
115
- projectRoot: this.projectRoot
155
+ projectRoot: this.projectRoot,
156
+ features: {
157
+ hasNuxt3: isNuxt3
158
+ }
116
159
  };
117
160
  } else if (dependencies.next) {
161
+ const nextVersion = dependencies.next;
162
+ const isNext13 = this.isVersionGte(nextVersion, '13.0.0');
163
+
118
164
  framework = {
119
165
  name: 'nextjs',
120
166
  type: 'nextjs',
167
+ version: nextVersion,
168
+ majorVersion: this.getMajorVersion(nextVersion),
121
169
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/node'],
122
170
  hasRouter: true,
123
- projectRoot: this.projectRoot
171
+ projectRoot: this.projectRoot,
172
+ features: {
173
+ hasNextAppRouter: isNext13
174
+ }
124
175
  };
125
176
  } else if (dependencies['@remix-run/react'] || dependencies['@remix-run/dev']) {
177
+ const remixVersion = dependencies['@remix-run/react'] || dependencies['@remix-run/dev'];
126
178
  framework = {
127
179
  name: 'remix',
128
180
  type: 'remix',
181
+ version: remixVersion,
182
+ majorVersion: this.getMajorVersion(remixVersion),
129
183
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
130
184
  hasRouter: true,
131
- projectRoot: this.projectRoot
185
+ projectRoot: this.projectRoot,
186
+ features: {}
132
187
  };
133
188
  } else if (dependencies.react) {
189
+ const reactVersion = dependencies.react;
190
+ const isReact18 = this.isVersionGte(reactVersion, '18.0.0');
191
+
134
192
  framework = {
135
193
  name: 'react',
136
194
  type: 'react',
195
+ version: reactVersion,
196
+ majorVersion: this.getMajorVersion(reactVersion),
137
197
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
138
198
  hasRouter: !!dependencies['react-router-dom'] || !!dependencies['react-router'],
139
- projectRoot: this.projectRoot
199
+ projectRoot: this.projectRoot,
200
+ features: {
201
+ hasReact18: isReact18
202
+ }
140
203
  };
141
204
  } else if (dependencies.vue) {
205
+ const vueVersion = dependencies.vue;
206
+ const isVue3 = this.isVersionGte(vueVersion, '3.0.0');
207
+
142
208
  framework = {
143
209
  name: 'vue',
144
210
  type: 'vue',
211
+ version: vueVersion,
212
+ majorVersion: this.getMajorVersion(vueVersion),
145
213
  hasTypeScript: !!dependencies.typescript || !!dependencies['@vue/cli-service'],
146
214
  hasRouter: !!dependencies['vue-router'],
147
- projectRoot: this.projectRoot
215
+ projectRoot: this.projectRoot,
216
+ features: {
217
+ hasVue3: isVue3
218
+ }
148
219
  };
149
220
  } else if (dependencies['@angular/core']) {
221
+ const angularVersion = dependencies['@angular/core'];
222
+ const isAngular17 = this.isVersionGte(angularVersion, '17.0.0');
223
+
150
224
  framework = {
151
225
  name: 'angular',
152
226
  type: 'angular',
227
+ version: angularVersion,
228
+ majorVersion: this.getMajorVersion(angularVersion),
153
229
  hasTypeScript: true,
154
230
  hasRouter: true,
155
- projectRoot: this.projectRoot
231
+ projectRoot: this.projectRoot,
232
+ features: {
233
+ hasAngularStandalone: isAngular17
234
+ }
156
235
  };
157
236
  } else if (dependencies.svelte) {
237
+ const svelteVersion = dependencies.svelte;
238
+ const isSvelteKit = !!dependencies['@sveltejs/kit'];
239
+
158
240
  framework = {
159
241
  name: 'svelte',
160
242
  type: 'svelte',
243
+ version: svelteVersion,
244
+ majorVersion: this.getMajorVersion(svelteVersion),
161
245
  hasTypeScript: !!dependencies.typescript || !!dependencies['svelte-check'],
162
246
  hasRouter: !!dependencies['svelte-routing'] || !!dependencies['@sveltejs/kit'],
163
- projectRoot: this.projectRoot
247
+ projectRoot: this.projectRoot,
248
+ features: {
249
+ hasSvelteKit: isSvelteKit
250
+ }
164
251
  };
165
252
  } else if (dependencies.astro) {
253
+ const astroVersion = dependencies.astro;
166
254
  framework = {
167
255
  name: 'astro',
168
256
  type: 'astro',
257
+ version: astroVersion,
258
+ majorVersion: this.getMajorVersion(astroVersion),
169
259
  hasTypeScript: !!dependencies.typescript || !!dependencies['@astrojs/ts-plugin'],
170
260
  hasRouter: true,
171
- projectRoot: this.projectRoot
261
+ projectRoot: this.projectRoot,
262
+ features: {}
172
263
  };
173
264
  } else if (dependencies.gatsby) {
265
+ const gatsbyVersion = dependencies.gatsby;
174
266
  framework = {
175
267
  name: 'gatsby',
176
268
  type: 'gatsby',
269
+ version: gatsbyVersion,
270
+ majorVersion: this.getMajorVersion(gatsbyVersion),
177
271
  hasTypeScript: !!dependencies.typescript || !!dependencies['@types/react'],
178
272
  hasRouter: true,
179
- projectRoot: this.projectRoot
273
+ projectRoot: this.projectRoot,
274
+ features: {}
180
275
  };
181
276
  }
182
277
 
@@ -868,30 +963,61 @@ export const onClientEntry = () => {
868
963
  : 'process.env.HUMANBEHAVIOR_API_KEY!';
869
964
 
870
965
  const importStatement = `import { HumanBehaviorProvider } from 'humanbehavior-js/react';`;
871
- const providerWrapper = `
872
- function App() {
873
- return (
874
- <HumanBehaviorProvider apiKey={${envVar}}>
875
- {/* Your existing app content */}
876
- </HumanBehaviorProvider>
877
- );
878
- }`;
879
966
 
880
- // Simple injection - in production, you'd want more sophisticated parsing
967
+ // Enhanced parsing for React 18+ features
968
+ const hasReact18 = this.framework?.features?.hasReact18;
969
+
970
+ // Handle different React patterns
881
971
  if (content.includes('function App()') || content.includes('const App =')) {
882
- return content.replace(
883
- /(function App\(\)|const App =)/,
884
- `${importStatement}\n\n$1`
885
- ).replace(
886
- /return \(([\s\S]*?)\);/,
972
+ // Add import statement
973
+ let modifiedContent = content.replace(
974
+ /(import.*?from.*?['"]react['"];?)/,
975
+ `$1\n${importStatement}`
976
+ );
977
+
978
+ // If no React import found, add it at the top
979
+ if (!modifiedContent.includes(importStatement)) {
980
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
981
+ }
982
+
983
+ // Wrap the App component return with HumanBehaviorProvider
984
+ modifiedContent = modifiedContent.replace(
985
+ /(return\s*\([\s\S]*?\)\s*;)/,
887
986
  `return (
888
987
  <HumanBehaviorProvider apiKey={${envVar}}>
889
988
  $1
890
989
  </HumanBehaviorProvider>
891
990
  );`
892
991
  );
992
+
993
+ return modifiedContent;
994
+ }
995
+
996
+ // Handle React 18+ createRoot pattern
997
+ if (hasReact18 && content.includes('createRoot')) {
998
+ let modifiedContent = content.replace(
999
+ /(import.*?from.*?['"]react['"];?)/,
1000
+ `$1\n${importStatement}`
1001
+ );
1002
+
1003
+ if (!modifiedContent.includes(importStatement)) {
1004
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1005
+ }
1006
+
1007
+ // Wrap the root render with HumanBehaviorProvider
1008
+ modifiedContent = modifiedContent.replace(
1009
+ /(root\.render\s*\([\s\S]*?\)\s*;)/,
1010
+ `root.render(
1011
+ <HumanBehaviorProvider apiKey={${envVar}}>
1012
+ $1
1013
+ </HumanBehaviorProvider>
1014
+ );`
1015
+ );
1016
+
1017
+ return modifiedContent;
893
1018
  }
894
1019
 
1020
+ // Fallback: simple injection
895
1021
  return `${importStatement}\n\n${content}`;
896
1022
  }
897
1023
 
@@ -1026,29 +1152,69 @@ export default function App()`
1026
1152
  }
1027
1153
 
1028
1154
  const importStatement = `import { HumanBehaviorPlugin } from 'humanbehavior-js/vue';`;
1029
- const pluginUsage = `app.use(HumanBehaviorPlugin, {
1155
+
1156
+ // Enhanced Vue 3 support with version detection
1157
+ const hasVue3 = this.framework?.features?.hasVue3;
1158
+
1159
+ if (hasVue3) {
1160
+ // Vue 3 with Composition API
1161
+ const pluginUsage = `app.use(HumanBehaviorPlugin, {
1030
1162
  apiKey: import.meta.env.VITE_HUMANBEHAVIOR_API_KEY
1031
1163
  });`;
1032
1164
 
1033
- // Handle both Vue 2 and Vue 3 patterns
1034
- if (content.includes('createApp')) {
1035
- // Vue 3
1036
- return content.replace(
1037
- /import.*from.*['"]vue['"]/,
1038
- `$&\n${importStatement}`
1039
- ).replace(
1040
- /app\.mount\(/,
1041
- `${pluginUsage}\n\napp.mount(`
1042
- );
1165
+ let modifiedContent = content;
1166
+
1167
+ // Add import statement
1168
+ if (!content.includes(importStatement)) {
1169
+ modifiedContent = content.replace(
1170
+ /(import.*?from.*?['"]vue['"];?)/,
1171
+ `$1\n${importStatement}`
1172
+ );
1173
+
1174
+ // If no Vue import found, add it at the top
1175
+ if (!modifiedContent.includes(importStatement)) {
1176
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1177
+ }
1178
+ }
1179
+
1180
+ // Handle createApp pattern
1181
+ if (content.includes('createApp')) {
1182
+ modifiedContent = modifiedContent.replace(
1183
+ /(app\.mount\(.*?\))/,
1184
+ `${pluginUsage}\n\n$1`
1185
+ );
1186
+ }
1187
+
1188
+ return modifiedContent;
1043
1189
  } else {
1044
- // Vue 2
1045
- return content.replace(
1046
- /import.*from.*['"]vue['"]/,
1047
- `$&\n${importStatement}`
1048
- ).replace(
1049
- /new Vue\(/,
1050
- `${pluginUsage}\n\nnew Vue(`
1051
- );
1190
+ // Vue 2 with Options API
1191
+ const pluginUsage = `Vue.use(HumanBehaviorPlugin, {
1192
+ apiKey: process.env.VUE_APP_HUMANBEHAVIOR_API_KEY
1193
+ });`;
1194
+
1195
+ let modifiedContent = content;
1196
+
1197
+ // Add import statement
1198
+ if (!content.includes(importStatement)) {
1199
+ modifiedContent = content.replace(
1200
+ /(import.*?from.*?['"]vue['"];?)/,
1201
+ `$1\n${importStatement}`
1202
+ );
1203
+
1204
+ if (!modifiedContent.includes(importStatement)) {
1205
+ modifiedContent = `${importStatement}\n\n${modifiedContent}`;
1206
+ }
1207
+ }
1208
+
1209
+ // Handle new Vue pattern
1210
+ if (content.includes('new Vue')) {
1211
+ modifiedContent = modifiedContent.replace(
1212
+ /(new Vue\(.*?\))/,
1213
+ `${pluginUsage}\n\n$1`
1214
+ );
1215
+ }
1216
+
1217
+ return modifiedContent;
1052
1218
  }
1053
1219
  }
1054
1220
 
@@ -1214,16 +1380,30 @@ if (typeof window !== 'undefined') {
1214
1380
  return content;
1215
1381
  }
1216
1382
 
1217
- // Add runtime config by inserting it after the opening brace
1218
- return content.replace(
1219
- /export default defineNuxtConfig\(\{/,
1220
- `export default defineNuxtConfig({
1383
+ // Enhanced Nuxt 3 support with version detection
1384
+ const hasNuxt3 = this.framework?.features?.hasNuxt3;
1385
+
1386
+ if (hasNuxt3) {
1387
+ // Nuxt 3 with runtime config
1388
+ return content.replace(
1389
+ /export default defineNuxtConfig\(\{/,
1390
+ `export default defineNuxtConfig({
1221
1391
  runtimeConfig: {
1222
1392
  public: {
1223
1393
  humanBehaviorApiKey: process.env.NUXT_PUBLIC_HUMANBEHAVIOR_API_KEY
1224
1394
  }
1225
1395
  },`
1226
- );
1396
+ );
1397
+ } else {
1398
+ // Nuxt 2 with env config
1399
+ return content.replace(
1400
+ /export default \{/,
1401
+ `export default {
1402
+ env: {
1403
+ humanBehaviorApiKey: process.env.HUMANBEHAVIOR_API_KEY
1404
+ },`
1405
+ );
1406
+ }
1227
1407
  }
1228
1408
 
1229
1409
  private injectGatsbyLayout(content: string): string {
@@ -14,6 +14,16 @@ export interface FrameworkInfo {
14
14
  hasTypeScript?: boolean;
15
15
  hasRouter?: boolean;
16
16
  projectRoot?: string;
17
+ version?: string;
18
+ majorVersion?: number;
19
+ features?: {
20
+ hasReact18?: boolean;
21
+ hasVue3?: boolean;
22
+ hasNuxt3?: boolean;
23
+ hasAngularStandalone?: boolean;
24
+ hasNextAppRouter?: boolean;
25
+ hasSvelteKit?: boolean;
26
+ };
17
27
  }
18
28
 
19
29
  export interface RemoteAIServiceConfig {