lua-cli 2.4.1 → 2.5.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.5.0] - 2025-10-07
9
+
10
+ ### ✨ New Features
11
+ - **Direct Property Access for UserDataInstance**: Now supports intuitive property access using Proxy pattern
12
+ - Access user data with `user.name` instead of `user.data.name`
13
+ - Set properties directly with `user.name = "John"`
14
+ - Full backward compatibility maintained - `user.data.name` still works
15
+ - Proper enumeration support for `Object.keys()` and `in` operator
16
+
17
+ ### 🔧 Improvements
18
+ - **Reduced Sensitive Field Filtering**: Sanitization now only removes `agentId` and `userId`
19
+ - Allows access to more user data fields while maintaining essential privacy
20
+ - Custom keys and tokens are now accessible in tools
21
+
22
+ ### 📖 Documentation
23
+ - **Comprehensive UserDataInstance Documentation**: Added full API reference with examples
24
+
25
+ ### Technical Details
26
+ - Enhanced Proxy implementation with proper trap handlers for get, set, has, ownKeys, and getOwnPropertyDescriptor
27
+ - Reserved properties (`data`, `userAPI`, `update`, `clear`, `toJSON`) protected from proxy interception
28
+ - Maintains all existing methods and behavior while adding new access patterns
29
+
8
30
  ## [1.3.2-alpha.3] - 2025-09-25
9
31
 
10
32
  ### 🚀 Major Rewrite
@@ -0,0 +1,621 @@
1
+ # UserDataInstance API Reference
2
+
3
+ ## Overview
4
+
5
+ `UserDataInstance` is a powerful, proxy-enhanced class that provides a fluent API for managing user-specific data in Lua AI tools. It automatically handles data sanitization, provides intuitive property access, and includes methods for updating and clearing user data.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Installation](#installation)
11
+ - [Quick Start](#quick-start)
12
+ - [API Reference](#api-reference)
13
+ - [Property Access](#property-access)
14
+ - [Methods](#methods)
15
+ - [Examples](#examples)
16
+ - [Best Practices](#best-practices)
17
+ - [TypeScript Support](#typescript-support)
18
+
19
+ ## Features
20
+
21
+ ✨ **Direct Property Access** - Access data with `user.name` instead of `user.data.name`
22
+ 🔒 **Automatic Sanitization** - Removes sensitive fields (agentId, userId) automatically
23
+ 🔄 **Async Updates** - Built-in methods for updating and clearing user data
24
+ 📝 **Console-Friendly** - Clean output when logging with `console.log()`
25
+ 🎯 **Type-Safe** - Full TypeScript support with proper type definitions
26
+ ⚡ **Proxy-Powered** - Seamless property access via JavaScript Proxy
27
+ 🔙 **Backward Compatible** - Works with both new and old access patterns
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install lua-cli
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```typescript
38
+ import { UserDataTool } from 'lua-cli';
39
+
40
+ // In your LuaSkill tool
41
+ class MyTool extends LuaTool {
42
+ async execute(input: any, context: ToolContext) {
43
+ // Access user data through context
44
+ const user = context.user;
45
+
46
+ // Direct property access (NEW! ✨)
47
+ console.log(user.name);
48
+ console.log(user.email);
49
+ console.log(user.preferences);
50
+
51
+ // Set properties directly
52
+ user.favoriteColor = "blue";
53
+
54
+ // Update on server
55
+ await user.update({ favoriteColor: "blue" });
56
+
57
+ return { success: true };
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## API Reference
63
+
64
+ ### Constructor
65
+
66
+ ```typescript
67
+ constructor(api: UserDataAPI, data: UserData)
68
+ ```
69
+
70
+ **Parameters:**
71
+ - `api` - The UserDataAPI instance for making API calls
72
+ - `data` - The user data from the API (will be sanitized automatically)
73
+
74
+ **Returns:** A proxied instance that allows direct access to data properties
75
+
76
+ **Note:** You typically don't need to instantiate this directly. It's provided through the `context.user` object in your tools.
77
+
78
+ ## Property Access
79
+
80
+ ### Direct Access (Recommended ✨)
81
+
82
+ ```typescript
83
+ // Reading properties
84
+ const name = user.name;
85
+ const email = user.email;
86
+ const settings = user.settings;
87
+
88
+ // Setting properties (updates local instance only)
89
+ user.name = "John Doe";
90
+ user.email = "john@example.com";
91
+ user.settings = { theme: "dark" };
92
+
93
+ // Checking if property exists
94
+ if ('name' in user) {
95
+ console.log('User has a name');
96
+ }
97
+ ```
98
+
99
+ ### Traditional Access (Still Supported)
100
+
101
+ ```typescript
102
+ // Reading through .data property
103
+ const name = user.data.name;
104
+ const email = user.data.email;
105
+
106
+ // Setting through .data property
107
+ user.data.name = "John Doe";
108
+ ```
109
+
110
+ ### Property Enumeration
111
+
112
+ ```typescript
113
+ // Get all user data keys
114
+ const keys = Object.keys(user); // Returns all data keys + methods
115
+
116
+ // Iterate over properties
117
+ for (const key in user) {
118
+ console.log(`${key}: ${user[key]}`);
119
+ }
120
+ ```
121
+
122
+ ## Methods
123
+
124
+ ### `update(data: Record<string, any>): Promise<any>`
125
+
126
+ Updates the user's data on the server and locally.
127
+
128
+ **Parameters:**
129
+ - `data` - Object containing the fields to update or add
130
+
131
+ **Returns:** Promise resolving to the updated sanitized user data
132
+
133
+ **Throws:** Error if the update fails
134
+
135
+ **Example:**
136
+ ```typescript
137
+ // Update single field
138
+ await user.update({ name: "John Doe" });
139
+
140
+ // Update multiple fields
141
+ await user.update({
142
+ name: "John Doe",
143
+ email: "john@example.com",
144
+ preferences: {
145
+ theme: "dark",
146
+ notifications: true
147
+ }
148
+ });
149
+
150
+ // Access updated data
151
+ console.log(user.name); // "John Doe"
152
+ console.log(user.preferences.theme); // "dark"
153
+ ```
154
+
155
+ ### `clear(): Promise<boolean>`
156
+
157
+ Clears all user data for the current user on the server.
158
+
159
+ **Returns:** Promise resolving to `true` if clearing was successful
160
+
161
+ **Throws:** Error if the clear operation fails
162
+
163
+ **Example:**
164
+ ```typescript
165
+ try {
166
+ const success = await user.clear();
167
+ if (success) {
168
+ console.log('User data cleared successfully');
169
+ }
170
+ } catch (error) {
171
+ console.error('Failed to clear user data');
172
+ }
173
+ ```
174
+
175
+ ### `toJSON(): Record<string, any>`
176
+
177
+ Custom serialization method used when converting to JSON or logging.
178
+
179
+ **Returns:** The sanitized user data object
180
+
181
+ **Example:**
182
+ ```typescript
183
+ // Automatic usage in JSON.stringify
184
+ const json = JSON.stringify(user);
185
+
186
+ // Explicit usage
187
+ const dataObject = user.toJSON();
188
+ ```
189
+
190
+ ## Data Sanitization
191
+
192
+ The `UserDataInstance` automatically removes sensitive fields before storing data locally:
193
+
194
+ **Removed Fields:**
195
+ - `agentId`
196
+ - `userId`
197
+
198
+ **Accessible Fields:** All other fields including:
199
+ - `name`, `email`, `phone`
200
+ - Custom data fields
201
+ - API keys and tokens (if stored in user data)
202
+ - Preferences and settings
203
+
204
+ ```typescript
205
+ // Server returns:
206
+ {
207
+ userId: "12345", // ❌ Removed
208
+ agentId: "agent-123", // ❌ Removed
209
+ name: "John Doe", // ✅ Accessible
210
+ email: "john@example.com", // ✅ Accessible
211
+ customKey: "value" // ✅ Accessible
212
+ }
213
+
214
+ // Local user instance has:
215
+ {
216
+ name: "John Doe",
217
+ email: "john@example.com",
218
+ customKey: "value"
219
+ }
220
+ ```
221
+
222
+ ## Examples
223
+
224
+ ### Example 1: Storing User Preferences
225
+
226
+ ```typescript
227
+ class PreferencesTool extends LuaTool {
228
+ schema = {
229
+ input: z.object({
230
+ theme: z.enum(['light', 'dark']).optional(),
231
+ language: z.string().optional(),
232
+ notifications: z.boolean().optional()
233
+ }),
234
+ output: z.object({
235
+ message: z.string(),
236
+ preferences: z.any()
237
+ })
238
+ };
239
+
240
+ async execute(input: any, context: ToolContext) {
241
+ const user = context.user;
242
+
243
+ // Get current preferences or initialize
244
+ const currentPrefs = user.preferences || {};
245
+
246
+ // Update with new values
247
+ const newPrefs = {
248
+ ...currentPrefs,
249
+ ...input
250
+ };
251
+
252
+ // Save to server
253
+ await user.update({ preferences: newPrefs });
254
+
255
+ return {
256
+ message: 'Preferences updated successfully',
257
+ preferences: user.preferences
258
+ };
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### Example 2: User Profile Management
264
+
265
+ ```typescript
266
+ class ProfileTool extends LuaTool {
267
+ schema = {
268
+ input: z.object({
269
+ action: z.enum(['get', 'update', 'clear']),
270
+ profile: z.object({
271
+ firstName: z.string().optional(),
272
+ lastName: z.string().optional(),
273
+ bio: z.string().optional(),
274
+ avatar: z.string().url().optional()
275
+ }).optional()
276
+ }),
277
+ output: z.object({
278
+ success: z.boolean(),
279
+ profile: z.any().optional(),
280
+ message: z.string()
281
+ })
282
+ };
283
+
284
+ async execute(input: any, context: ToolContext) {
285
+ const user = context.user;
286
+
287
+ switch (input.action) {
288
+ case 'get':
289
+ return {
290
+ success: true,
291
+ profile: {
292
+ firstName: user.firstName,
293
+ lastName: user.lastName,
294
+ bio: user.bio,
295
+ avatar: user.avatar
296
+ },
297
+ message: 'Profile retrieved'
298
+ };
299
+
300
+ case 'update':
301
+ await user.update(input.profile);
302
+ return {
303
+ success: true,
304
+ profile: input.profile,
305
+ message: 'Profile updated successfully'
306
+ };
307
+
308
+ case 'clear':
309
+ await user.clear();
310
+ return {
311
+ success: true,
312
+ message: 'Profile cleared successfully'
313
+ };
314
+
315
+ default:
316
+ throw new Error('Invalid action');
317
+ }
318
+ }
319
+ }
320
+ ```
321
+
322
+ ### Example 3: Shopping Cart Persistence
323
+
324
+ ```typescript
325
+ class CartTool extends LuaTool {
326
+ schema = {
327
+ input: z.object({
328
+ action: z.enum(['add', 'remove', 'get', 'clear']),
329
+ productId: z.string().optional(),
330
+ quantity: z.number().optional()
331
+ }),
332
+ output: z.object({
333
+ cart: z.array(z.any()),
334
+ total: z.number()
335
+ })
336
+ };
337
+
338
+ async execute(input: any, context: ToolContext) {
339
+ const user = context.user;
340
+
341
+ // Get current cart (direct access!)
342
+ let cart = user.cart || [];
343
+
344
+ switch (input.action) {
345
+ case 'add':
346
+ const existing = cart.find((item: any) =>
347
+ item.productId === input.productId
348
+ );
349
+
350
+ if (existing) {
351
+ existing.quantity += input.quantity;
352
+ } else {
353
+ cart.push({
354
+ productId: input.productId,
355
+ quantity: input.quantity
356
+ });
357
+ }
358
+
359
+ await user.update({ cart });
360
+ break;
361
+
362
+ case 'remove':
363
+ cart = cart.filter((item: any) =>
364
+ item.productId !== input.productId
365
+ );
366
+ await user.update({ cart });
367
+ break;
368
+
369
+ case 'clear':
370
+ await user.update({ cart: [] });
371
+ cart = [];
372
+ break;
373
+
374
+ case 'get':
375
+ // Just return current cart
376
+ break;
377
+ }
378
+
379
+ const total = cart.reduce((sum: number, item: any) =>
380
+ sum + (item.quantity || 0), 0
381
+ );
382
+
383
+ return { cart, total };
384
+ }
385
+ }
386
+ ```
387
+
388
+ ### Example 4: Session State Management
389
+
390
+ ```typescript
391
+ class SessionTool extends LuaTool {
392
+ async execute(input: any, context: ToolContext) {
393
+ const user = context.user;
394
+
395
+ // Track page visits
396
+ const visits = user.pageVisits || 0;
397
+ await user.update({ pageVisits: visits + 1 });
398
+
399
+ // Track last seen timestamp
400
+ await user.update({
401
+ lastSeen: new Date().toISOString(),
402
+ sessionCount: (user.sessionCount || 0) + 1
403
+ });
404
+
405
+ // Check if returning user
406
+ const isReturning = visits > 0;
407
+
408
+ return {
409
+ isReturning,
410
+ visits: user.pageVisits,
411
+ sessionCount: user.sessionCount,
412
+ lastSeen: user.lastSeen
413
+ };
414
+ }
415
+ }
416
+ ```
417
+
418
+ ### Example 5: Multi-Step Form Data
419
+
420
+ ```typescript
421
+ class FormStateTool extends LuaTool {
422
+ async execute(input: any, context: ToolContext) {
423
+ const user = context.user;
424
+
425
+ // Get or initialize form state
426
+ const formData = user.multiStepForm || {
427
+ step: 1,
428
+ completed: {},
429
+ currentData: {}
430
+ };
431
+
432
+ // Update current step data
433
+ formData.completed[input.step] = true;
434
+ formData.currentData = {
435
+ ...formData.currentData,
436
+ ...input.data
437
+ };
438
+
439
+ // Move to next step
440
+ formData.step = input.step + 1;
441
+
442
+ // Save state
443
+ await user.update({ multiStepForm: formData });
444
+
445
+ return {
446
+ currentStep: formData.step,
447
+ completedSteps: Object.keys(formData.completed),
448
+ isComplete: formData.step > 5
449
+ };
450
+ }
451
+ }
452
+ ```
453
+
454
+ ## Best Practices
455
+
456
+ ### ✅ DO
457
+
458
+ ```typescript
459
+ // Use direct property access for cleaner code
460
+ const name = user.name;
461
+
462
+ // Update multiple fields at once
463
+ await user.update({
464
+ field1: value1,
465
+ field2: value2
466
+ });
467
+
468
+ // Check for property existence before accessing
469
+ if ('preferences' in user) {
470
+ console.log(user.preferences);
471
+ }
472
+
473
+ // Initialize nested objects carefully
474
+ const prefs = user.preferences || {};
475
+ ```
476
+
477
+ ### ❌ DON'T
478
+
479
+ ```typescript
480
+ // Don't mutate and forget to call update()
481
+ user.name = "John";
482
+ // ❌ This only updates locally! Must call user.update()
483
+
484
+ // Don't assume sensitive fields are available
485
+ console.log(user.userId); // undefined (sanitized)
486
+ console.log(user.agentId); // undefined (sanitized)
487
+
488
+ // Don't make unnecessary update calls
489
+ await user.update({ field1: value1 });
490
+ await user.update({ field2: value2 }); // Combine these!
491
+ ```
492
+
493
+ ## TypeScript Support
494
+
495
+ ### Type Definitions
496
+
497
+ ```typescript
498
+ interface UserDataInstance {
499
+ data: Record<string, any>;
500
+
501
+ // Methods
502
+ update(data: Record<string, any>): Promise<any>;
503
+ clear(): Promise<boolean>;
504
+ toJSON(): Record<string, any>;
505
+
506
+ // Index signature for dynamic property access
507
+ [key: string]: any;
508
+ }
509
+ ```
510
+
511
+ ### Usage with Types
512
+
513
+ ```typescript
514
+ // Define your user data shape
515
+ interface MyUserData {
516
+ name: string;
517
+ email: string;
518
+ preferences: {
519
+ theme: 'light' | 'dark';
520
+ notifications: boolean;
521
+ };
522
+ }
523
+
524
+ // Access with type checking
525
+ const user = context.user;
526
+ const name: string = user.name;
527
+ const prefs: MyUserData['preferences'] = user.preferences;
528
+ ```
529
+
530
+ ## Console Output
531
+
532
+ The `UserDataInstance` includes custom serialization for clean console output:
533
+
534
+ ```typescript
535
+ console.log(user);
536
+ // Output:
537
+ // {
538
+ // name: "John Doe",
539
+ // email: "john@example.com",
540
+ // preferences: { theme: "dark" }
541
+ // }
542
+
543
+ // Methods and internal properties are hidden
544
+ // Only the actual user data is displayed
545
+ ```
546
+
547
+ ## Reserved Properties
548
+
549
+ The following properties are reserved and cannot be overwritten via proxy:
550
+
551
+ - `data` - The internal data storage
552
+ - `userAPI` - The API client (non-enumerable)
553
+ - `update` - The update method
554
+ - `clear` - The clear method
555
+ - `toJSON` - The serialization method
556
+
557
+ Attempting to set these will maintain the original instance behavior.
558
+
559
+ ## Performance Considerations
560
+
561
+ - **Proxy Overhead**: Minimal performance impact for property access
562
+ - **Update Batching**: Combine multiple field updates into a single `update()` call
563
+ - **Local Changes**: Setting properties directly only updates the local instance
564
+ - **Server Sync**: Always call `update()` to persist changes to the server
565
+
566
+ ## Backward Compatibility
567
+
568
+ The new direct property access pattern is fully backward compatible:
569
+
570
+ ```typescript
571
+ // Old pattern (still works)
572
+ user.data.name = "John";
573
+ await user.update({ name: user.data.name });
574
+
575
+ // New pattern (recommended)
576
+ user.name = "John";
577
+ await user.update({ name: user.name });
578
+
579
+ // Mixed usage (also works)
580
+ console.log(user.name); // Direct access
581
+ console.log(user.data.email); // Traditional access
582
+ ```
583
+
584
+ ## Error Handling
585
+
586
+ ```typescript
587
+ try {
588
+ await user.update({
589
+ name: "John Doe",
590
+ email: "john@example.com"
591
+ });
592
+ } catch (error) {
593
+ console.error('Failed to update user data:', error);
594
+ // Handle error appropriately
595
+ }
596
+
597
+ try {
598
+ await user.clear();
599
+ } catch (error) {
600
+ console.error('Failed to clear user data:', error);
601
+ }
602
+ ```
603
+
604
+ ## Related Resources
605
+
606
+ - [LuaTool Documentation](./TEMPLATE_GUIDE.md)
607
+ - [API Reference](./API_REFERENCE.md)
608
+ - [Getting Started](./GETTING_STARTED.md)
609
+ - [UserDataTool Example](./template/src/tools/UserDataTool.ts)
610
+
611
+ ## Support
612
+
613
+ For issues, questions, or contributions:
614
+ - GitHub: [lua-ai-global/lua-cli](https://github.com/lua-ai-global/lua-cli)
615
+ - Email: stefan@heylua.ai
616
+
617
+ ---
618
+
619
+ **Version:** 2.5.0
620
+ **Last Updated:** October 7, 2025
621
+ **License:** MIT
@@ -3,14 +3,16 @@ import { UserDataAPI } from "../types/index.js";
3
3
  /**
4
4
  * User data instance class providing a fluent API for managing user data
5
5
  * Automatically sanitizes sensitive fields and provides methods for updating and clearing data
6
+ * Supports direct property access (e.g., user.name) instead of user.data.name
6
7
  */
7
8
  export default class UserDataInstance {
8
9
  data: Record<string, any>;
9
10
  private userAPI;
10
11
  /**
11
- * Creates a new UserDataInstance
12
+ * Creates a new UserDataInstance with proxy support for direct property access
12
13
  * @param api - The UserDataAPI instance for making API calls
13
14
  * @param data - The user data from the API (will be sanitized automatically)
15
+ * @returns Proxied instance that allows direct access to data properties
14
16
  */
15
17
  constructor(api: UserDataAPI, data: UserData);
16
18
  /**
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * User data instance class providing a fluent API for managing user data
3
3
  * Automatically sanitizes sensitive fields and provides methods for updating and clearing data
4
+ * Supports direct property access (e.g., user.name) instead of user.data.name
4
5
  */
5
6
  export default class UserDataInstance {
6
7
  /**
7
- * Creates a new UserDataInstance
8
+ * Creates a new UserDataInstance with proxy support for direct property access
8
9
  * @param api - The UserDataAPI instance for making API calls
9
10
  * @param data - The user data from the API (will be sanitized automatically)
11
+ * @returns Proxied instance that allows direct access to data properties
10
12
  */
11
13
  constructor(api, data) {
12
14
  this.data = this.sanitizeData(data);
@@ -17,6 +19,60 @@ export default class UserDataInstance {
17
19
  enumerable: false,
18
20
  configurable: true
19
21
  });
22
+ // Return a proxy that allows direct property access
23
+ return new Proxy(this, {
24
+ get(target, prop, receiver) {
25
+ // If the property exists on the instance itself, return it
26
+ if (prop in target) {
27
+ return Reflect.get(target, prop, receiver);
28
+ }
29
+ // Otherwise, try to get it from the data object
30
+ if (typeof prop === 'string' && prop in target.data) {
31
+ return target.data[prop];
32
+ }
33
+ return undefined;
34
+ },
35
+ set(target, prop, value, receiver) {
36
+ // Reserved properties that should be set on the instance itself
37
+ const reservedProps = ['data', 'userAPI', 'update', 'clear', 'toJSON'];
38
+ if (typeof prop === 'string' && reservedProps.includes(prop)) {
39
+ return Reflect.set(target, prop, value, receiver);
40
+ }
41
+ // All other properties get set on the data object
42
+ if (typeof prop === 'string') {
43
+ target.data[prop] = value;
44
+ return true;
45
+ }
46
+ return false;
47
+ },
48
+ has(target, prop) {
49
+ // Check if property exists on instance or in data
50
+ return prop in target || (typeof prop === 'string' && prop in target.data);
51
+ },
52
+ ownKeys(target) {
53
+ // Return both instance keys and data keys
54
+ const instanceKeys = Reflect.ownKeys(target);
55
+ const dataKeys = Object.keys(target.data);
56
+ return [...new Set([...instanceKeys, ...dataKeys])];
57
+ },
58
+ getOwnPropertyDescriptor(target, prop) {
59
+ // First check if it's an instance property
60
+ const instanceDesc = Reflect.getOwnPropertyDescriptor(target, prop);
61
+ if (instanceDesc) {
62
+ return instanceDesc;
63
+ }
64
+ // Then check if it's a data property
65
+ if (typeof prop === 'string' && prop in target.data) {
66
+ return {
67
+ configurable: true,
68
+ enumerable: true,
69
+ writable: true,
70
+ value: target.data[prop]
71
+ };
72
+ }
73
+ return undefined;
74
+ }
75
+ });
20
76
  }
21
77
  /**
22
78
  * Removes sensitive fields from the data before storing
@@ -31,7 +87,7 @@ export default class UserDataInstance {
31
87
  // Create a copy of the data to avoid mutating the original
32
88
  const sanitized = { ...data };
33
89
  // Remove sensitive fields
34
- const sensitiveFields = ['apiKey', 'agentId', 'userId', 'token', 'secret', 'key'];
90
+ const sensitiveFields = ['agentId', 'userId'];
35
91
  sensitiveFields.forEach(field => {
36
92
  delete sanitized[field];
37
93
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "Command-line interface for Lua AI platform - develop, test, and deploy LuaSkills with custom tools",
5
5
  "readmeFilename": "README.md",
6
6
  "main": "dist/api-exports.js",
@@ -57,6 +57,7 @@
57
57
  "CLI_REFERENCE.md",
58
58
  "API_REFERENCE.md",
59
59
  "TEMPLATE_GUIDE.md",
60
+ "USER_DATA_INSTANCE.md",
60
61
  "CHANGELOG.md",
61
62
  "LICENSE"
62
63
  ],