@@ -83,6 +83,12 @@ export class UserProfileManager {
8383 const id = `profile_${ Date . now ( ) } _${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 9 ) } ` ;
8484 const now = Date . now ( ) ;
8585
86+ const cleanedData : UserProfileData = {
87+ preferences : safeArray ( profileData . preferences ) ,
88+ patterns : safeArray ( profileData . patterns ) ,
89+ workflows : safeArray ( profileData . workflows ) ,
90+ } ;
91+
8692 const stmt = this . db . prepare ( `
8793 INSERT INTO user_profiles (
8894 id, user_id, display_name, user_name, user_email,
@@ -98,13 +104,13 @@ export class UserProfileManager {
98104 displayName ,
99105 userName ,
100106 userEmail ,
101- JSON . stringify ( profileData ) ,
107+ JSON . stringify ( cleanedData ) ,
102108 now ,
103109 now ,
104110 promptsAnalyzed
105111 ) ;
106112
107- this . addChangelog ( id , 1 , "create" , "Initial profile creation" , profileData ) ;
113+ this . addChangelog ( id , 1 , "create" , "Initial profile creation" , cleanedData ) ;
108114
109115 return id ;
110116 }
@@ -117,6 +123,12 @@ export class UserProfileManager {
117123 ) : void {
118124 const now = Date . now ( ) ;
119125
126+ const cleanedData : UserProfileData = {
127+ preferences : safeArray ( profileData . preferences ) ,
128+ patterns : safeArray ( profileData . patterns ) ,
129+ workflows : safeArray ( profileData . workflows ) ,
130+ } ;
131+
120132 const getVersionStmt = this . db . prepare ( `SELECT version FROM user_profiles WHERE id = ?` ) ;
121133 const versionRow = getVersionStmt . get ( profileId ) as any ;
122134 const newVersion = ( versionRow ?. version || 0 ) + 1 ;
@@ -131,14 +143,14 @@ export class UserProfileManager {
131143 ` ) ;
132144
133145 updateStmt . run (
134- JSON . stringify ( profileData ) ,
146+ JSON . stringify ( cleanedData ) ,
135147 newVersion ,
136148 now ,
137149 additionalPromptsAnalyzed ,
138150 profileId
139151 ) ;
140152
141- this . addChangelog ( profileId , newVersion , "update" , changeSummary , profileData ) ;
153+ this . addChangelog ( profileId , newVersion , "update" , changeSummary , cleanedData ) ;
142154
143155 this . cleanupOldChangelogs ( profileId ) ;
144156 }
@@ -268,25 +280,29 @@ export class UserProfileManager {
268280
269281 mergeProfileData ( existing : UserProfileData , updates : Partial < UserProfileData > ) : UserProfileData {
270282 const merged : UserProfileData = {
271- preferences : safeArray ( existing ?. preferences ) ,
272- patterns : safeArray ( existing ?. patterns ) ,
273- workflows : safeArray ( existing ?. workflows ) ,
283+ preferences : this . ensureArray ( existing ?. preferences ) ,
284+ patterns : this . ensureArray ( existing ?. patterns ) ,
285+ workflows : this . ensureArray ( existing ?. workflows ) ,
274286 } ;
275287
276288 if ( updates . preferences ) {
277- for ( const newPref of updates . preferences ) {
289+ const incomingPrefs = this . ensureArray ( updates . preferences ) ;
290+ for ( const newPref of incomingPrefs ) {
278291 const existingIndex = merged . preferences . findIndex (
279292 ( p ) => p . category === newPref . category && p . description === newPref . description
280293 ) ;
281294
282295 if ( existingIndex >= 0 ) {
283- const existing = merged . preferences [ existingIndex ] ;
284- if ( existing ) {
296+ const existingItem = merged . preferences [ existingIndex ] ;
297+ if ( existingItem ) {
285298 merged . preferences [ existingIndex ] = {
286299 ...newPref ,
287- confidence : Math . min ( 1 , existing . confidence + 0.1 ) ,
300+ confidence : Math . min ( 1 , ( existingItem . confidence || 0 ) + 0.1 ) ,
288301 evidence : [
289- ...new Set ( [ ...safeArray ( existing . evidence ) , ...safeArray ( newPref . evidence ) ] ) ,
302+ ...new Set ( [
303+ ...this . ensureArray ( existingItem . evidence ) ,
304+ ...this . ensureArray ( newPref . evidence ) ,
305+ ] ) ,
290306 ] . slice ( 0 , 5 ) ,
291307 lastUpdated : Date . now ( ) ,
292308 } ;
@@ -296,22 +312,23 @@ export class UserProfileManager {
296312 }
297313 }
298314
299- merged . preferences . sort ( ( a , b ) => b . confidence - a . confidence ) ;
315+ merged . preferences . sort ( ( a , b ) => ( b . confidence || 0 ) - ( a . confidence || 0 ) ) ;
300316 merged . preferences = merged . preferences . slice ( 0 , CONFIG . userProfileMaxPreferences ) ;
301317 }
302318
303319 if ( updates . patterns ) {
304- for ( const newPattern of updates . patterns ) {
320+ const incomingPatterns = this . ensureArray ( updates . patterns ) ;
321+ for ( const newPattern of incomingPatterns ) {
305322 const existingIndex = merged . patterns . findIndex (
306323 ( p ) => p . category === newPattern . category && p . description === newPattern . description
307324 ) ;
308325
309326 if ( existingIndex >= 0 ) {
310- const existing = merged . patterns [ existingIndex ] ;
311- if ( existing ) {
327+ const existingItem = merged . patterns [ existingIndex ] ;
328+ if ( existingItem ) {
312329 merged . patterns [ existingIndex ] = {
313330 ...newPattern ,
314- frequency : existing . frequency + 1 ,
331+ frequency : ( existingItem . frequency || 1 ) + 1 ,
315332 lastSeen : Date . now ( ) ,
316333 } ;
317334 }
@@ -320,35 +337,48 @@ export class UserProfileManager {
320337 }
321338 }
322339
323- merged . patterns . sort ( ( a , b ) => b . frequency - a . frequency ) ;
340+ merged . patterns . sort ( ( a , b ) => ( b . frequency || 0 ) - ( a . frequency || 0 ) ) ;
324341 merged . patterns = merged . patterns . slice ( 0 , CONFIG . userProfileMaxPatterns ) ;
325342 }
326343
327344 if ( updates . workflows ) {
328- for ( const newWorkflow of updates . workflows ) {
345+ const incomingWorkflows = this . ensureArray ( updates . workflows ) ;
346+ for ( const newWorkflow of incomingWorkflows ) {
329347 const existingIndex = merged . workflows . findIndex (
330348 ( w ) => w . description === newWorkflow . description
331349 ) ;
332350
333351 if ( existingIndex >= 0 ) {
334- const existing = merged . workflows [ existingIndex ] ;
335- if ( existing ) {
352+ const existingItem = merged . workflows [ existingIndex ] ;
353+ if ( existingItem ) {
336354 merged . workflows [ existingIndex ] = {
337355 ...newWorkflow ,
338- frequency : existing . frequency + 1 ,
356+ frequency : ( existingItem . frequency || 1 ) + 1 ,
339357 } ;
340358 }
341359 } else {
342360 merged . workflows . push ( { ...newWorkflow , frequency : 1 } ) ;
343361 }
344362 }
345363
346- merged . workflows . sort ( ( a , b ) => b . frequency - a . frequency ) ;
364+ merged . workflows . sort ( ( a , b ) => ( b . frequency || 0 ) - ( a . frequency || 0 ) ) ;
347365 merged . workflows = merged . workflows . slice ( 0 , CONFIG . userProfileMaxWorkflows ) ;
348366 }
349367
350368 return merged ;
351369 }
370+
371+ private ensureArray ( val : any ) : any [ ] {
372+ if ( typeof val === "string" ) {
373+ try {
374+ const parsed = JSON . parse ( val ) ;
375+ return Array . isArray ( parsed ) ? parsed : [ ] ;
376+ } catch {
377+ return [ ] ;
378+ }
379+ }
380+ return Array . isArray ( val ) ? val : [ ] ;
381+ }
352382}
353383
354384export const userProfileManager = new UserProfileManager ( ) ;
0 commit comments