@contractspec/lib.example-shared-ui 6.0.5 → 6.0.7
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.
- package/.turbo/turbo-build.log +90 -84
- package/AGENTS.md +43 -25
- package/CHANGELOG.md +11 -0
- package/README.md +63 -35
- package/dist/EvolutionDashboard.js +9 -9
- package/dist/EvolutionSidebar.js +15 -15
- package/dist/LocalDataIndicator.js +3 -3
- package/dist/MarkdownView.d.ts +0 -7
- package/dist/MarkdownView.js +76 -172
- package/dist/PersonalizationInsights.js +12 -12
- package/dist/SaveToStudioButton.js +2 -2
- package/dist/SpecDrivenTemplateShell.d.ts +1 -1
- package/dist/SpecDrivenTemplateShell.js +10 -10
- package/dist/SpecEditorPanel.js +3 -3
- package/dist/TemplateShell.js +10 -10
- package/dist/browser/EvolutionDashboard.js +9 -9
- package/dist/browser/EvolutionSidebar.js +15 -15
- package/dist/browser/LocalDataIndicator.js +3 -3
- package/dist/browser/MarkdownView.js +76 -172
- package/dist/browser/PersonalizationInsights.js +12 -12
- package/dist/browser/SaveToStudioButton.js +2 -2
- package/dist/browser/SpecDrivenTemplateShell.js +10 -10
- package/dist/browser/SpecEditorPanel.js +3 -3
- package/dist/browser/TemplateShell.js +10 -10
- package/dist/browser/hooks/index.js +29 -29
- package/dist/browser/index.js +193 -286
- package/dist/browser/lib/component-registry.js +1 -1
- package/dist/browser/markdown/formatPresentationName.js +9 -0
- package/dist/browser/markdown/useMarkdownPresentation.js +65 -0
- package/dist/hooks/index.d.ts +3 -3
- package/dist/hooks/index.js +29 -29
- package/dist/index.d.ts +12 -11
- package/dist/index.js +193 -286
- package/dist/lib/component-registry.js +1 -1
- package/dist/markdown/formatPresentationName.d.ts +1 -0
- package/dist/markdown/formatPresentationName.js +10 -0
- package/dist/markdown/useMarkdownPresentation.d.ts +21 -0
- package/dist/markdown/useMarkdownPresentation.js +66 -0
- package/dist/node/EvolutionDashboard.js +9 -9
- package/dist/node/EvolutionSidebar.js +15 -15
- package/dist/node/LocalDataIndicator.js +3 -3
- package/dist/node/MarkdownView.js +76 -172
- package/dist/node/PersonalizationInsights.js +12 -12
- package/dist/node/SaveToStudioButton.js +2 -2
- package/dist/node/SpecDrivenTemplateShell.js +10 -10
- package/dist/node/SpecEditorPanel.js +3 -3
- package/dist/node/TemplateShell.js +10 -10
- package/dist/node/hooks/index.js +29 -29
- package/dist/node/index.js +193 -286
- package/dist/node/lib/component-registry.js +1 -1
- package/dist/node/markdown/formatPresentationName.js +9 -0
- package/dist/node/markdown/useMarkdownPresentation.js +65 -0
- package/dist/utils/index.d.ts +1 -1
- package/package.json +40 -13
- package/src/EvolutionDashboard.tsx +415 -415
- package/src/EvolutionSidebar.tsx +245 -245
- package/src/LocalDataIndicator.tsx +28 -28
- package/src/MarkdownView.tsx +119 -372
- package/src/OverlayContextProvider.tsx +272 -272
- package/src/PersonalizationInsights.tsx +232 -232
- package/src/SaveToStudioButton.tsx +51 -51
- package/src/SpecDrivenTemplateShell.tsx +59 -59
- package/src/SpecEditorPanel.tsx +138 -138
- package/src/TemplateShell.tsx +50 -50
- package/src/bundles/ExampleTemplateBundle.ts +78 -78
- package/src/hooks/index.ts +3 -3
- package/src/hooks/useBehaviorTracking.ts +252 -252
- package/src/hooks/useEvolution.ts +437 -437
- package/src/hooks/useRegistryTemplates.ts +42 -42
- package/src/hooks/useSpecContent.ts +214 -214
- package/src/hooks/useWorkflowComposer.ts +567 -567
- package/src/index.ts +12 -11
- package/src/lib/component-registry.tsx +40 -40
- package/src/lib/runtime-context.tsx +31 -31
- package/src/lib/types.ts +57 -57
- package/src/markdown/formatPresentationName.ts +9 -0
- package/src/markdown/useMarkdownPresentation.ts +107 -0
- package/src/overlay-types.ts +15 -15
- package/src/utils/fetchPresentationData.ts +13 -13
- package/src/utils/generateSpecFromTemplate.ts +29 -29
- package/src/utils/index.ts +1 -1
- package/tsconfig.json +8 -8
|
@@ -7,58 +7,58 @@ import type { TemplateId } from '../lib/types';
|
|
|
7
7
|
* Behavior event types
|
|
8
8
|
*/
|
|
9
9
|
export type BehaviorEventType =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
| 'template_view'
|
|
11
|
+
| 'mode_change'
|
|
12
|
+
| 'spec_edit'
|
|
13
|
+
| 'canvas_interaction'
|
|
14
|
+
| 'presentation_view'
|
|
15
|
+
| 'feature_usage'
|
|
16
|
+
| 'error'
|
|
17
|
+
| 'navigation';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Behavior event data
|
|
21
21
|
*/
|
|
22
22
|
export interface BehaviorEvent {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
type: BehaviorEventType;
|
|
24
|
+
timestamp: Date;
|
|
25
|
+
templateId: TemplateId;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Behavior summary for a session
|
|
31
31
|
*/
|
|
32
32
|
export interface BehaviorSummary {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
totalEvents: number;
|
|
34
|
+
sessionDuration: number;
|
|
35
|
+
mostUsedTemplates: { templateId: TemplateId; count: number }[];
|
|
36
|
+
mostUsedModes: { mode: string; count: number }[];
|
|
37
|
+
featuresUsed: string[];
|
|
38
|
+
unusedFeatures: string[];
|
|
39
|
+
errorCount: number;
|
|
40
|
+
recommendations: string[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Hook return type
|
|
45
45
|
*/
|
|
46
46
|
export interface UseBehaviorTrackingReturn {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
/** Track a behavior event */
|
|
48
|
+
trackEvent: (
|
|
49
|
+
type: BehaviorEventType,
|
|
50
|
+
metadata?: Record<string, unknown>
|
|
51
|
+
) => void;
|
|
52
|
+
/** Get behavior summary */
|
|
53
|
+
getSummary: () => BehaviorSummary;
|
|
54
|
+
/** Get events for a specific type */
|
|
55
|
+
getEventsByType: (type: BehaviorEventType) => BehaviorEvent[];
|
|
56
|
+
/** Total event count */
|
|
57
|
+
eventCount: number;
|
|
58
|
+
/** Session start time */
|
|
59
|
+
sessionStart: Date;
|
|
60
|
+
/** Clear all tracked data */
|
|
61
|
+
clear: () => void;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -70,16 +70,16 @@ const BEHAVIOR_STORAGE_KEY = 'contractspec-behavior-data';
|
|
|
70
70
|
* All available features in the sandbox
|
|
71
71
|
*/
|
|
72
72
|
const ALL_FEATURES = [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
'playground',
|
|
74
|
+
'specs',
|
|
75
|
+
'builder',
|
|
76
|
+
'markdown',
|
|
77
|
+
'evolution',
|
|
78
|
+
'canvas_add',
|
|
79
|
+
'canvas_delete',
|
|
80
|
+
'spec_save',
|
|
81
|
+
'spec_validate',
|
|
82
|
+
'ai_suggestions',
|
|
83
83
|
];
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -87,241 +87,241 @@ const ALL_FEATURES = [
|
|
|
87
87
|
* Provides insights into usage patterns and feature adoption.
|
|
88
88
|
*/
|
|
89
89
|
export function useBehaviorTracking(
|
|
90
|
-
|
|
90
|
+
templateId: TemplateId
|
|
91
91
|
): UseBehaviorTrackingReturn {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
const [events, setEvents] = useState<BehaviorEvent[]>([]);
|
|
93
|
+
const sessionStartRef = useRef<Date>(new Date());
|
|
94
|
+
const [eventCount, setEventCount] = useState(0);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
96
|
+
// Load persisted events on mount
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
try {
|
|
99
|
+
const stored = localStorage.getItem(BEHAVIOR_STORAGE_KEY);
|
|
100
|
+
if (stored) {
|
|
101
|
+
const data = JSON.parse(stored) as {
|
|
102
|
+
events: (Omit<BehaviorEvent, 'timestamp'> & { timestamp: string })[];
|
|
103
|
+
sessionStart: string;
|
|
104
|
+
};
|
|
105
|
+
setEvents(
|
|
106
|
+
data.events.map((e) => ({
|
|
107
|
+
...e,
|
|
108
|
+
timestamp: new Date(e.timestamp),
|
|
109
|
+
}))
|
|
110
|
+
);
|
|
111
|
+
sessionStartRef.current = new Date(data.sessionStart);
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
// Ignore storage errors
|
|
115
|
+
}
|
|
116
|
+
}, []);
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
118
|
+
// Persist events when they change
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (events.length > 0) {
|
|
121
|
+
try {
|
|
122
|
+
localStorage.setItem(
|
|
123
|
+
BEHAVIOR_STORAGE_KEY,
|
|
124
|
+
JSON.stringify({
|
|
125
|
+
events: events.map((e) => ({
|
|
126
|
+
...e,
|
|
127
|
+
timestamp: e.timestamp.toISOString(),
|
|
128
|
+
})),
|
|
129
|
+
sessionStart: sessionStartRef.current.toISOString(),
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
} catch {
|
|
133
|
+
// Ignore storage errors
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}, [events]);
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Track a behavior event
|
|
140
|
+
*/
|
|
141
|
+
const trackEvent = useCallback(
|
|
142
|
+
(type: BehaviorEventType, metadata?: Record<string, unknown>) => {
|
|
143
|
+
const event: BehaviorEvent = {
|
|
144
|
+
type,
|
|
145
|
+
timestamp: new Date(),
|
|
146
|
+
templateId,
|
|
147
|
+
metadata,
|
|
148
|
+
};
|
|
149
|
+
setEvents((prev) => [...prev, event]);
|
|
150
|
+
setEventCount((prev) => prev + 1);
|
|
151
|
+
},
|
|
152
|
+
[templateId]
|
|
153
|
+
);
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Get events by type
|
|
157
|
+
*/
|
|
158
|
+
const getEventsByType = useCallback(
|
|
159
|
+
(type: BehaviorEventType): BehaviorEvent[] => {
|
|
160
|
+
return events.filter((e) => e.type === type);
|
|
161
|
+
},
|
|
162
|
+
[events]
|
|
163
|
+
);
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Get behavior summary
|
|
167
|
+
*/
|
|
168
|
+
const getSummary = useCallback((): BehaviorSummary => {
|
|
169
|
+
const now = new Date();
|
|
170
|
+
const sessionDuration = now.getTime() - sessionStartRef.current.getTime();
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
// Count templates
|
|
173
|
+
const templateCounts = new Map<TemplateId, number>();
|
|
174
|
+
for (const event of events) {
|
|
175
|
+
const count = templateCounts.get(event.templateId) ?? 0;
|
|
176
|
+
templateCounts.set(event.templateId, count + 1);
|
|
177
|
+
}
|
|
178
|
+
const mostUsedTemplates = Array.from(templateCounts.entries())
|
|
179
|
+
.map(([templateId, count]) => ({ templateId, count }))
|
|
180
|
+
.sort((a, b) => b.count - a.count)
|
|
181
|
+
.slice(0, 3);
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
183
|
+
// Count modes from mode_change events
|
|
184
|
+
const modeCounts = new Map<string, number>();
|
|
185
|
+
for (const event of events) {
|
|
186
|
+
if (event.type === 'mode_change' && event.metadata?.mode) {
|
|
187
|
+
const mode = event.metadata.mode as string;
|
|
188
|
+
const count = modeCounts.get(mode) ?? 0;
|
|
189
|
+
modeCounts.set(mode, count + 1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const mostUsedModes = Array.from(modeCounts.entries())
|
|
193
|
+
.map(([mode, count]) => ({ mode, count }))
|
|
194
|
+
.sort((a, b) => b.count - a.count);
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
196
|
+
// Track features used
|
|
197
|
+
const featuresUsed = new Set<string>();
|
|
198
|
+
for (const event of events) {
|
|
199
|
+
if (event.type === 'mode_change' && event.metadata?.mode) {
|
|
200
|
+
featuresUsed.add(event.metadata.mode as string);
|
|
201
|
+
}
|
|
202
|
+
if (event.type === 'feature_usage' && event.metadata?.feature) {
|
|
203
|
+
featuresUsed.add(event.metadata.feature as string);
|
|
204
|
+
}
|
|
205
|
+
if (event.type === 'canvas_interaction') {
|
|
206
|
+
const action = event.metadata?.action as string;
|
|
207
|
+
if (action === 'add') featuresUsed.add('canvas_add');
|
|
208
|
+
if (action === 'delete') featuresUsed.add('canvas_delete');
|
|
209
|
+
}
|
|
210
|
+
if (event.type === 'spec_edit') {
|
|
211
|
+
const action = event.metadata?.action as string;
|
|
212
|
+
if (action === 'save') featuresUsed.add('spec_save');
|
|
213
|
+
if (action === 'validate') featuresUsed.add('spec_validate');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
// Find unused features
|
|
218
|
+
const unusedFeatures = ALL_FEATURES.filter((f) => !featuresUsed.has(f));
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
// Count errors
|
|
221
|
+
const errorCount = events.filter((e) => e.type === 'error').length;
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
223
|
+
// Generate recommendations
|
|
224
|
+
const recommendations = generateRecommendations(
|
|
225
|
+
Array.from(featuresUsed),
|
|
226
|
+
unusedFeatures,
|
|
227
|
+
mostUsedModes,
|
|
228
|
+
events.length
|
|
229
|
+
);
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
231
|
+
return {
|
|
232
|
+
totalEvents: events.length,
|
|
233
|
+
sessionDuration,
|
|
234
|
+
mostUsedTemplates,
|
|
235
|
+
mostUsedModes,
|
|
236
|
+
featuresUsed: Array.from(featuresUsed),
|
|
237
|
+
unusedFeatures,
|
|
238
|
+
errorCount,
|
|
239
|
+
recommendations,
|
|
240
|
+
};
|
|
241
|
+
}, [events]);
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Clear all tracking data
|
|
245
|
+
*/
|
|
246
|
+
const clear = useCallback(() => {
|
|
247
|
+
setEvents([]);
|
|
248
|
+
setEventCount(0);
|
|
249
|
+
sessionStartRef.current = new Date();
|
|
250
|
+
localStorage.removeItem(BEHAVIOR_STORAGE_KEY);
|
|
251
|
+
}, []);
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
253
|
+
return useMemo(
|
|
254
|
+
() => ({
|
|
255
|
+
trackEvent,
|
|
256
|
+
getSummary,
|
|
257
|
+
getEventsByType,
|
|
258
|
+
eventCount,
|
|
259
|
+
sessionStart: sessionStartRef.current,
|
|
260
|
+
clear,
|
|
261
|
+
}),
|
|
262
|
+
[trackEvent, getSummary, getEventsByType, eventCount, clear]
|
|
263
|
+
);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
/**
|
|
267
267
|
* Generate recommendations based on behavior
|
|
268
268
|
*/
|
|
269
269
|
function generateRecommendations(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
270
|
+
featuresUsed: string[],
|
|
271
|
+
unusedFeatures: string[],
|
|
272
|
+
mostUsedModes: { mode: string; count: number }[],
|
|
273
|
+
totalEvents: number
|
|
274
274
|
): string[] {
|
|
275
|
-
|
|
275
|
+
const recommendations: string[] = [];
|
|
276
276
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
277
|
+
// Recommend unused features
|
|
278
|
+
if (unusedFeatures.includes('evolution')) {
|
|
279
|
+
recommendations.push(
|
|
280
|
+
'Try the AI Evolution mode to get automated improvement suggestions'
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
284
|
+
if (unusedFeatures.includes('markdown')) {
|
|
285
|
+
recommendations.push(
|
|
286
|
+
'Use Markdown preview to see documentation for your specs'
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
289
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
290
|
+
if (unusedFeatures.includes('builder')) {
|
|
291
|
+
recommendations.push(
|
|
292
|
+
'Explore the Visual Builder to design your UI components'
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
295
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
296
|
+
if (
|
|
297
|
+
!featuresUsed.includes('spec_validate') &&
|
|
298
|
+
featuresUsed.includes('specs')
|
|
299
|
+
) {
|
|
300
|
+
recommendations.push("Don't forget to validate your specs before saving");
|
|
301
|
+
}
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
303
|
+
if (
|
|
304
|
+
featuresUsed.includes('evolution') &&
|
|
305
|
+
!featuresUsed.includes('ai_suggestions')
|
|
306
|
+
) {
|
|
307
|
+
recommendations.push(
|
|
308
|
+
'Generate AI suggestions to get actionable improvement recommendations'
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
312
|
+
// Time-based recommendations
|
|
313
|
+
if (totalEvents > 50) {
|
|
314
|
+
recommendations.push(
|
|
315
|
+
'Great engagement! Consider saving your work regularly'
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
319
|
+
// Mode variety recommendations
|
|
320
|
+
if (mostUsedModes.length === 1) {
|
|
321
|
+
recommendations.push(
|
|
322
|
+
'Try different modes to explore all sandbox capabilities'
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
return recommendations;
|
|
327
327
|
}
|