@memberjunction/metadata-sync 2.46.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/README.md +552 -0
- package/bin/debug.js +7 -0
- package/bin/run +17 -0
- package/bin/run.js +6 -0
- package/dist/commands/init/index.d.ts +7 -0
- package/dist/commands/init/index.js +130 -0
- package/dist/commands/init/index.js.map +1 -0
- package/dist/commands/pull/index.d.ts +18 -0
- package/dist/commands/pull/index.js +313 -0
- package/dist/commands/pull/index.js.map +1 -0
- package/dist/commands/push/index.d.ts +15 -0
- package/dist/commands/push/index.js +286 -0
- package/dist/commands/push/index.js.map +1 -0
- package/dist/commands/status/index.d.ts +10 -0
- package/dist/commands/status/index.js +124 -0
- package/dist/commands/status/index.js.map +1 -0
- package/dist/commands/watch/index.d.ts +15 -0
- package/dist/commands/watch/index.js +210 -0
- package/dist/commands/watch/index.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +69 -0
- package/dist/config.js.map +1 -0
- package/dist/hooks/init.d.ts +3 -0
- package/dist/hooks/init.js +51 -0
- package/dist/hooks/init.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/provider-utils.d.ts +13 -0
- package/dist/lib/provider-utils.js +117 -0
- package/dist/lib/provider-utils.js.map +1 -0
- package/dist/lib/sync-engine.d.ts +49 -0
- package/dist/lib/sync-engine.js +254 -0
- package/dist/lib/sync-engine.js.map +1 -0
- package/oclif.manifest.json +196 -0
- package/package.json +85 -0
package/README.md
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# MemberJunction Metadata Sync
|
|
2
|
+
|
|
3
|
+
A CLI tool for synchronizing MemberJunction database metadata with local file system representations. This tool enables developers and non-technical users to manage MJ metadata using their preferred editors and version control systems while maintaining the database as the source of truth.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
MemberJunction is a powerful metadata-driven system where configuration, business logic, AI prompts, templates, and more are stored as metadata in the database. This approach provides tremendous flexibility and runtime configurability, but it can create friction in modern development workflows.
|
|
8
|
+
|
|
9
|
+
### Why This Tool Matters
|
|
10
|
+
|
|
11
|
+
**For Developers:**
|
|
12
|
+
- **Full IDE Support**: Edit complex prompts and templates with syntax highlighting, IntelliSense, and all your favorite editor features
|
|
13
|
+
- **Version Control**: Track every change with Git - see diffs, blame, history, and collaborate through pull requests
|
|
14
|
+
- **Branch-based Development**: Work on features in isolation, test changes, and merge when ready
|
|
15
|
+
- **CI/CD Integration**: Automatically deploy metadata changes as code moves through environments
|
|
16
|
+
- **Bulk Operations**: Use familiar command-line tools (grep, sed, find) to make sweeping changes
|
|
17
|
+
- **Offline Development**: Work on metadata without database connectivity
|
|
18
|
+
|
|
19
|
+
**For Non-Technical Users:**
|
|
20
|
+
- **Familiar Tools**: Edit prompts in Word, Notepad++, or any text editor
|
|
21
|
+
- **No Database Access Needed**: IT can set up sync, users just edit files
|
|
22
|
+
- **Folder Organization**: Intuitive file/folder structure instead of database IDs
|
|
23
|
+
- **Easy Sharing**: Send prompt files via email or shared drives
|
|
24
|
+
- **Simple Backups**: Copy/paste folders for personal backups
|
|
25
|
+
|
|
26
|
+
**For Organizations:**
|
|
27
|
+
- **Migration Path**: Metadata flows naturally from dev → staging → production with code
|
|
28
|
+
- **Compliance**: Full audit trail through version control
|
|
29
|
+
- **Collaboration**: Multiple team members can work on different metadata simultaneously
|
|
30
|
+
- **Disaster Recovery**: File-based backups complement database backups
|
|
31
|
+
- **Cross-System Sync**: Export from one MJ instance, import to another
|
|
32
|
+
|
|
33
|
+
### The Best of Both Worlds
|
|
34
|
+
|
|
35
|
+
This tool preserves the power of MJ's metadata-driven architecture while adding the convenience of file-based workflows. The database remains the source of truth for runtime operations, while files become the medium for creation, editing, and deployment.
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
|
|
39
|
+
The Metadata Sync tool bridges the gap between database-stored metadata and file-based workflows by:
|
|
40
|
+
- Pulling metadata entities from database to JSON files with external file support
|
|
41
|
+
- Pushing local file changes back to the database
|
|
42
|
+
- Supporting embedded collections for related entities
|
|
43
|
+
- Enabling version control for all MJ metadata through Git
|
|
44
|
+
- Supporting CI/CD workflows for metadata deployment
|
|
45
|
+
- Providing a familiar file-based editing experience
|
|
46
|
+
|
|
47
|
+
## Key Features
|
|
48
|
+
|
|
49
|
+
### Hybrid File Storage
|
|
50
|
+
- **JSON files**: Store structured metadata for entities
|
|
51
|
+
- **External files**: Store large text fields (prompts, templates, etc.) in appropriate formats (.md, .html, .sql)
|
|
52
|
+
- **File references**: Use `@file:filename.ext` to link external files from JSON
|
|
53
|
+
|
|
54
|
+
### Embedded Collections (NEW)
|
|
55
|
+
- **Related Entities**: Store related records as arrays within parent JSON files
|
|
56
|
+
- **Hierarchical References**: Use `@parent:` and `@root:` to reference parent/root entity fields
|
|
57
|
+
- **Automatic Metadata**: Related entities maintain their own primaryKey and sync metadata
|
|
58
|
+
- **Nested Support**: Support for multiple levels of nested relationships
|
|
59
|
+
|
|
60
|
+
### Synchronization Operations
|
|
61
|
+
- **Pull**: Download metadata from database to local files
|
|
62
|
+
- Optionally pull related entities based on configuration
|
|
63
|
+
- Filter support for selective pulling
|
|
64
|
+
- **Push**: Upload local file changes to database
|
|
65
|
+
- Process embedded collections automatically
|
|
66
|
+
- Verbose mode (`-v`) for detailed output
|
|
67
|
+
- **Status**: Show what would change without making modifications
|
|
68
|
+
|
|
69
|
+
### Development Workflow Integration
|
|
70
|
+
- Watch mode for automatic syncing during development
|
|
71
|
+
- Dry-run mode to preview changes
|
|
72
|
+
- CI/CD mode for automated deployments
|
|
73
|
+
- Integration with existing mj.config.cjs configuration
|
|
74
|
+
|
|
75
|
+
## Supported Entities
|
|
76
|
+
|
|
77
|
+
### Phase 1: AI Prompts (Current)
|
|
78
|
+
- Full support for all AI Prompt fields
|
|
79
|
+
- Markdown files for prompt content
|
|
80
|
+
- Category-based organization
|
|
81
|
+
- AI Prompt Models as embedded collections
|
|
82
|
+
|
|
83
|
+
### Future Phases
|
|
84
|
+
- Templates
|
|
85
|
+
- AI Models
|
|
86
|
+
- AI Vendors
|
|
87
|
+
- Query definitions
|
|
88
|
+
- Any MJ entity with metadata
|
|
89
|
+
|
|
90
|
+
## File Structure
|
|
91
|
+
|
|
92
|
+
The tool uses a hierarchical directory structure with cascading defaults:
|
|
93
|
+
- Each top-level directory represents an entity type
|
|
94
|
+
- `.mj-sync.json` files define entities and base defaults
|
|
95
|
+
- `.mj-folder.json` files define folder-specific defaults (optional)
|
|
96
|
+
- All JSON files within are treated as records of that entity type
|
|
97
|
+
- External files (`.md`, `.html`, etc.) are referenced from the JSON files
|
|
98
|
+
- Defaults cascade down through the folder hierarchy
|
|
99
|
+
|
|
100
|
+
### Example Structure
|
|
101
|
+
```
|
|
102
|
+
metadata/
|
|
103
|
+
├── .mj-sync.json # Global sync configuration
|
|
104
|
+
├── ai-prompts/
|
|
105
|
+
│ ├── .mj-sync.json # Defines entity: "AI Prompts"
|
|
106
|
+
│ ├── customer-service/
|
|
107
|
+
│ │ ├── .mj-folder.json # Folder metadata (CategoryID, etc.)
|
|
108
|
+
│ │ ├── greeting.json # AI Prompt record with embedded models
|
|
109
|
+
│ │ ├── greeting.prompt.md # Prompt content (referenced)
|
|
110
|
+
│ │ └── greeting.notes.md # Notes field (referenced)
|
|
111
|
+
│ └── analytics/
|
|
112
|
+
│ ├── .mj-folder.json # Folder metadata (CategoryID, etc.)
|
|
113
|
+
│ ├── daily-report.json # AI Prompt record
|
|
114
|
+
│ └── daily-report.prompt.md # Prompt content (referenced)
|
|
115
|
+
└── templates/
|
|
116
|
+
├── .mj-sync.json # Defines entity: "Templates"
|
|
117
|
+
├── email/
|
|
118
|
+
│ ├── .mj-folder.json # Folder metadata
|
|
119
|
+
│ ├── welcome.json # Template record
|
|
120
|
+
│ └── welcome.template.html # Template content (referenced)
|
|
121
|
+
└── reports/
|
|
122
|
+
├── .mj-folder.json # Folder metadata
|
|
123
|
+
├── invoice.json # Template record
|
|
124
|
+
└── invoice.template.html # Template content (referenced)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## JSON Metadata Format
|
|
128
|
+
|
|
129
|
+
### Individual Record (e.g., ai-prompts/customer-service/greeting.json)
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"fields": {
|
|
133
|
+
"Name": "Customer Greeting",
|
|
134
|
+
"Description": "Friendly customer service greeting",
|
|
135
|
+
"TypeID": "@lookup:AI Prompt Types.Name=Chat",
|
|
136
|
+
"CategoryID": "@lookup:AI Prompt Categories.Name=Customer Service",
|
|
137
|
+
"Temperature": 0.7,
|
|
138
|
+
"MaxTokens": 1000,
|
|
139
|
+
"Prompt": "@file:greeting.prompt.md",
|
|
140
|
+
"Notes": "@file:../shared/notes/greeting-notes.md",
|
|
141
|
+
"SystemPrompt": "@url:https://raw.githubusercontent.com/company/prompts/main/system/customer-service.md"
|
|
142
|
+
},
|
|
143
|
+
"primaryKey": {
|
|
144
|
+
"ID": "550e8400-e29b-41d4-a716-446655440000"
|
|
145
|
+
},
|
|
146
|
+
"sync": {
|
|
147
|
+
"lastModified": "2024-01-15T10:30:00Z",
|
|
148
|
+
"checksum": "sha256:abcd1234..."
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Record with Embedded Collections (NEW)
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"fields": {
|
|
157
|
+
"Name": "Customer Service Chat",
|
|
158
|
+
"Description": "Main customer service prompt",
|
|
159
|
+
"TypeID": "@lookup:AI Prompt Types.Name=Chat",
|
|
160
|
+
"TemplateText": "@file:customer-service.md",
|
|
161
|
+
"Status": "Active"
|
|
162
|
+
},
|
|
163
|
+
"relatedEntities": {
|
|
164
|
+
"MJ: AI Prompt Models": [
|
|
165
|
+
{
|
|
166
|
+
"fields": {
|
|
167
|
+
"PromptID": "@parent:ID",
|
|
168
|
+
"ModelID": "@lookup:AI Models.Name=GPT 4.1",
|
|
169
|
+
"VendorID": "@lookup:MJ: AI Vendors.Name=OpenAI",
|
|
170
|
+
"Priority": 1,
|
|
171
|
+
"Status": "Active"
|
|
172
|
+
},
|
|
173
|
+
"primaryKey": {
|
|
174
|
+
"ID": "BFA2433E-F36B-1410-8DB0-00021F8B792E"
|
|
175
|
+
},
|
|
176
|
+
"sync": {
|
|
177
|
+
"lastModified": "2025-06-07T17:18:31.687Z",
|
|
178
|
+
"checksum": "a642ebea748cb1f99467af2a7e6f4ffd3649761be27453b988af973bed57f070"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"fields": {
|
|
183
|
+
"PromptID": "@parent:ID",
|
|
184
|
+
"ModelID": "@lookup:AI Models.Name=Claude 4 Sonnet",
|
|
185
|
+
"Priority": 2,
|
|
186
|
+
"Status": "Active"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
"primaryKey": {
|
|
192
|
+
"ID": "C2A1433E-F36B-1410-8DB0-00021F8B792E"
|
|
193
|
+
},
|
|
194
|
+
"sync": {
|
|
195
|
+
"lastModified": "2025-06-07T17:18:31.698Z",
|
|
196
|
+
"checksum": "7cbd241cbf0d67c068c1434e572a78c87bb31751cbfe7734bfd32f8cea17a2c9"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Composite Primary Key Example
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"primaryKey": {
|
|
205
|
+
"UserID": "550e8400-e29b-41d4-a716-446655440000",
|
|
206
|
+
"RoleID": "660f9400-f39c-51e5-b827-557766551111"
|
|
207
|
+
},
|
|
208
|
+
"fields": {
|
|
209
|
+
"GrantedAt": "2024-01-15T10:30:00Z",
|
|
210
|
+
"GrantedBy": "@lookup:Users.Email=admin@company.com",
|
|
211
|
+
"ExpiresAt": "2025-01-15T10:30:00Z",
|
|
212
|
+
"Notes": "@file:user-role-notes.md"
|
|
213
|
+
},
|
|
214
|
+
"sync": {
|
|
215
|
+
"lastModified": "2024-01-15T10:30:00Z",
|
|
216
|
+
"checksum": "sha256:abcd1234..."
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Default Value Inheritance
|
|
222
|
+
|
|
223
|
+
The tool implements a cascading inheritance system for field defaults, similar to CSS or OOP inheritance:
|
|
224
|
+
|
|
225
|
+
1. **Entity-level defaults** (in `.mj-sync.json`) - Base defaults for all records
|
|
226
|
+
2. **Folder-level defaults** (in `.mj-folder.json`) - Override/extend entity defaults
|
|
227
|
+
3. **Nested folder defaults** - Override/extend parent folder defaults
|
|
228
|
+
4. **Record-level values** - Override all inherited defaults
|
|
229
|
+
|
|
230
|
+
### Inheritance Example
|
|
231
|
+
```
|
|
232
|
+
ai-prompts/.mj-sync.json → Temperature: 0.7, MaxTokens: 1500
|
|
233
|
+
├── customer-service/.mj-folder.json → Temperature: 0.8 (overrides)
|
|
234
|
+
│ ├── greeting.json → Uses Temperature: 0.8, MaxTokens: 1500
|
|
235
|
+
│ └── escalation/.mj-folder.json → Temperature: 0.6 (overrides again)
|
|
236
|
+
│ └── urgent.json → Temperature: 0.9 (record override)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Final values for `urgent.json`:
|
|
240
|
+
- Temperature: 0.9 (from record)
|
|
241
|
+
- MaxTokens: 1500 (from entity defaults)
|
|
242
|
+
- All other fields from folder hierarchy
|
|
243
|
+
|
|
244
|
+
## Special Conventions
|
|
245
|
+
|
|
246
|
+
The tool supports special reference types that can be used in ANY field that accepts text content. These references are processed during push/pull operations to handle external content, lookups, and environment-specific values.
|
|
247
|
+
|
|
248
|
+
### Primary Key Handling
|
|
249
|
+
The tool automatically detects primary key fields from entity metadata:
|
|
250
|
+
- **Single primary keys**: Most common, stored as `{"ID": "value"}` or `{"CustomKeyName": "value"}`
|
|
251
|
+
- **Composite primary keys**: Multiple fields that together form the primary key
|
|
252
|
+
- **Auto-detection**: Tool reads entity metadata to determine primary key structure
|
|
253
|
+
- **No hardcoding**: Works with any primary key field name(s)
|
|
254
|
+
|
|
255
|
+
### @file: References
|
|
256
|
+
When a field value starts with `@file:`, the tool will:
|
|
257
|
+
1. Read content from the specified file for push operations
|
|
258
|
+
2. Write content to the specified file for pull operations
|
|
259
|
+
3. Track both files for change detection
|
|
260
|
+
|
|
261
|
+
Examples:
|
|
262
|
+
- `@file:greeting.prompt.md` - File in same directory as JSON
|
|
263
|
+
- `@file:./shared/common-prompt.md` - Relative path
|
|
264
|
+
- `@file:../templates/standard-header.md` - Parent directory reference
|
|
265
|
+
|
|
266
|
+
### @url: References
|
|
267
|
+
When a field value starts with `@url:`, the tool will:
|
|
268
|
+
1. Fetch content from the URL during push operations
|
|
269
|
+
2. Cache the content with appropriate headers
|
|
270
|
+
3. Support both HTTP(S) and file:// protocols
|
|
271
|
+
|
|
272
|
+
Examples:
|
|
273
|
+
- `@url:https://example.com/prompts/greeting.md` - Remote content
|
|
274
|
+
- `@url:https://raw.githubusercontent.com/company/prompts/main/customer.md` - GitHub raw content
|
|
275
|
+
- `@url:file:///shared/network/drive/prompts/standard.md` - Local file URL
|
|
276
|
+
|
|
277
|
+
### @lookup: References (ENHANCED)
|
|
278
|
+
Enable entity relationships using human-readable values:
|
|
279
|
+
- Basic syntax: `@lookup:EntityName.FieldName=Value`
|
|
280
|
+
- Auto-create syntax: `@lookup:EntityName.FieldName=Value?create`
|
|
281
|
+
- With additional fields: `@lookup:EntityName.FieldName=Value?create&Field2=Value2`
|
|
282
|
+
|
|
283
|
+
Examples:
|
|
284
|
+
- `@lookup:AI Prompt Types.Name=Chat` - Fails if not found
|
|
285
|
+
- `@lookup:AI Prompt Categories.Name=Examples?create` - Creates if missing
|
|
286
|
+
- `@lookup:AI Prompt Categories.Name=Examples?create&Description=Example prompts` - Creates with description
|
|
287
|
+
|
|
288
|
+
### @parent: References (NEW)
|
|
289
|
+
Reference fields from the immediate parent entity in embedded collections:
|
|
290
|
+
- `@parent:ID` - Get the parent's ID field
|
|
291
|
+
- `@parent:Name` - Get the parent's Name field
|
|
292
|
+
- Works with any field from the parent entity
|
|
293
|
+
|
|
294
|
+
### @root: References (NEW)
|
|
295
|
+
Reference fields from the root entity in nested structures:
|
|
296
|
+
- `@root:ID` - Get the root entity's ID
|
|
297
|
+
- `@root:CategoryID` - Get the root's CategoryID
|
|
298
|
+
- Useful for deeply nested relationships
|
|
299
|
+
|
|
300
|
+
### @env: References
|
|
301
|
+
Support environment-specific values:
|
|
302
|
+
- `@env:VARIABLE_NAME`
|
|
303
|
+
- Useful for different environments (dev/staging/prod)
|
|
304
|
+
|
|
305
|
+
## CLI Commands
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Initialize a directory for metadata sync
|
|
309
|
+
mj-sync init
|
|
310
|
+
|
|
311
|
+
# Pull all AI Prompts from database to ai-prompts directory
|
|
312
|
+
mj-sync pull --entity="AI Prompts"
|
|
313
|
+
|
|
314
|
+
# Pull specific records by filter
|
|
315
|
+
mj-sync pull --entity="AI Prompts" --filter="CategoryID='customer-service-id'"
|
|
316
|
+
|
|
317
|
+
# Push all changes from current directory and subdirectories
|
|
318
|
+
mj-sync push
|
|
319
|
+
|
|
320
|
+
# Push only specific entity directory
|
|
321
|
+
mj-sync push --dir="ai-prompts"
|
|
322
|
+
|
|
323
|
+
# Push with verbose output (NEW)
|
|
324
|
+
mj-sync push -v
|
|
325
|
+
mj-sync push --verbose
|
|
326
|
+
|
|
327
|
+
# Dry run to see what would change
|
|
328
|
+
mj-sync push --dry-run
|
|
329
|
+
|
|
330
|
+
# Show status of local vs database
|
|
331
|
+
mj-sync status
|
|
332
|
+
|
|
333
|
+
# Watch for changes and auto-push
|
|
334
|
+
mj-sync watch
|
|
335
|
+
|
|
336
|
+
# CI/CD mode (push with no prompts)
|
|
337
|
+
mj-sync push --ci
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Configuration
|
|
341
|
+
|
|
342
|
+
The tool uses the existing `mj.config.cjs` for database configuration, eliminating the need for separate connection settings.
|
|
343
|
+
|
|
344
|
+
Configuration follows a hierarchical structure:
|
|
345
|
+
- **Root config**: Global settings for all operations
|
|
346
|
+
- **Entity configs**: Each entity directory has its own config defining the entity type
|
|
347
|
+
- **Inheritance**: All files within an entity directory are treated as records of that entity type
|
|
348
|
+
|
|
349
|
+
### Root Configuration (metadata/.mj-sync.json)
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"version": "1.0.0",
|
|
353
|
+
"push": {
|
|
354
|
+
"validateBeforePush": true,
|
|
355
|
+
"requireConfirmation": true
|
|
356
|
+
},
|
|
357
|
+
"watch": {
|
|
358
|
+
"debounceMs": 1000,
|
|
359
|
+
"ignorePatterns": ["*.tmp", "*.bak"]
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Entity Configuration (metadata/ai-prompts/.mj-sync.json)
|
|
365
|
+
```json
|
|
366
|
+
{
|
|
367
|
+
"entity": "AI Prompts",
|
|
368
|
+
"filePattern": "*.json",
|
|
369
|
+
"defaults": {
|
|
370
|
+
"TypeID": "@lookup:AI Prompt Types.Name=Chat",
|
|
371
|
+
"Temperature": 0.7,
|
|
372
|
+
"MaxTokens": 1500,
|
|
373
|
+
"Status": "Active"
|
|
374
|
+
},
|
|
375
|
+
"pull": {
|
|
376
|
+
"filter": "Status = 'Active'",
|
|
377
|
+
"relatedEntities": {
|
|
378
|
+
"MJ: AI Prompt Models": {
|
|
379
|
+
"entity": "MJ: AI Prompt Models",
|
|
380
|
+
"foreignKey": "ID",
|
|
381
|
+
"filter": "Status = 'Active'"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Folder Defaults (metadata/ai-prompts/customer-service/.mj-folder.json)
|
|
389
|
+
```json
|
|
390
|
+
{
|
|
391
|
+
"defaults": {
|
|
392
|
+
"CategoryID": "@lookup:AI Prompt Categories.Name=Customer Service",
|
|
393
|
+
"Temperature": 0.8,
|
|
394
|
+
"Tags": ["customer-service", "support"]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Nested Folder Defaults (metadata/ai-prompts/customer-service/escalation/.mj-folder.json)
|
|
400
|
+
```json
|
|
401
|
+
{
|
|
402
|
+
"defaults": {
|
|
403
|
+
"Tags": ["customer-service", "support", "escalation", "priority"],
|
|
404
|
+
"MaxTokens": 2000,
|
|
405
|
+
"Temperature": 0.6
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Embedded Collections (NEW)
|
|
411
|
+
|
|
412
|
+
The tool now supports managing related entities as embedded collections within parent JSON files. This is ideal for entities that have a strong parent-child relationship.
|
|
413
|
+
|
|
414
|
+
### Benefits
|
|
415
|
+
- **Single File Management**: Keep related data together
|
|
416
|
+
- **Atomic Operations**: Parent and children sync together
|
|
417
|
+
- **Cleaner Organization**: Fewer files to manage
|
|
418
|
+
- **Relationship Clarity**: Visual representation of data relationships
|
|
419
|
+
|
|
420
|
+
### Configuration for Pull
|
|
421
|
+
Configure which related entities to pull in `.mj-sync.json`:
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"entity": "AI Prompts",
|
|
425
|
+
"pull": {
|
|
426
|
+
"relatedEntities": {
|
|
427
|
+
"MJ: AI Prompt Models": {
|
|
428
|
+
"entity": "MJ: AI Prompt Models",
|
|
429
|
+
"foreignKey": "ID",
|
|
430
|
+
"filter": "Status = 'Active'"
|
|
431
|
+
},
|
|
432
|
+
"AI Prompt Parameters": {
|
|
433
|
+
"entity": "AI Prompt Parameters",
|
|
434
|
+
"foreignKey": "ID"
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Nested Related Entities
|
|
442
|
+
Support for multiple levels of nesting:
|
|
443
|
+
```json
|
|
444
|
+
{
|
|
445
|
+
"fields": {
|
|
446
|
+
"Name": "Parent Entity"
|
|
447
|
+
},
|
|
448
|
+
"relatedEntities": {
|
|
449
|
+
"Child Entity": [
|
|
450
|
+
{
|
|
451
|
+
"fields": {
|
|
452
|
+
"ParentID": "@parent:ID",
|
|
453
|
+
"Name": "Child 1"
|
|
454
|
+
},
|
|
455
|
+
"relatedEntities": {
|
|
456
|
+
"Grandchild Entity": [
|
|
457
|
+
{
|
|
458
|
+
"fields": {
|
|
459
|
+
"ChildID": "@parent:ID",
|
|
460
|
+
"RootID": "@root:ID",
|
|
461
|
+
"Name": "Grandchild 1"
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
]
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Console Output
|
|
473
|
+
|
|
474
|
+
### Normal Mode
|
|
475
|
+
Shows high-level progress:
|
|
476
|
+
```
|
|
477
|
+
Processing AI Prompts in demo/ai-prompts
|
|
478
|
+
↳ Processing 2 related MJ: AI Prompt Models records
|
|
479
|
+
Created: 1
|
|
480
|
+
Updated: 2
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Verbose Mode (-v flag)
|
|
484
|
+
Shows detailed field-level operations with hierarchical indentation:
|
|
485
|
+
```
|
|
486
|
+
Processing AI Prompts in demo/ai-prompts
|
|
487
|
+
Setting Name: "Example Greeting Prompt 3" -> "Example Greeting Prompt 3"
|
|
488
|
+
Setting Description: "A simple example prompt..." -> "A simple example prompt..."
|
|
489
|
+
↳ Processing 2 related MJ: AI Prompt Models records
|
|
490
|
+
Setting PromptID: "@parent:ID" -> "C2A1433E-F36B-1410-8DB0-00021F8B792E"
|
|
491
|
+
Setting ModelID: "@lookup:AI Models.Name=GPT 4.1" -> "123-456-789"
|
|
492
|
+
Setting Priority: 1 -> 1
|
|
493
|
+
✓ Created MJ: AI Prompt Models record
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
## Use Cases
|
|
497
|
+
|
|
498
|
+
### Developer Workflow
|
|
499
|
+
1. `mj-sync pull --entity="AI Prompts"` to get latest prompts with their models
|
|
500
|
+
2. Edit prompts and adjust model configurations in VS Code
|
|
501
|
+
3. Test locally with `mj-sync push --dry-run`
|
|
502
|
+
4. Commit changes to Git
|
|
503
|
+
5. PR review with diff visualization
|
|
504
|
+
6. CI/CD runs `mj-sync push --ci` on merge
|
|
505
|
+
|
|
506
|
+
### Content Team Workflow
|
|
507
|
+
1. Pull prompts to local directory
|
|
508
|
+
2. Edit in preferred markdown editor
|
|
509
|
+
3. Adjust model priorities in JSON
|
|
510
|
+
4. Preview changes
|
|
511
|
+
5. Push updates back to database
|
|
512
|
+
|
|
513
|
+
### CI/CD Integration
|
|
514
|
+
```yaml
|
|
515
|
+
- name: Push Metadata to Production
|
|
516
|
+
run: |
|
|
517
|
+
npm install -g @memberjunction/metadata-sync
|
|
518
|
+
mj-sync push --ci --entity="AI Prompts"
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
## Benefits
|
|
522
|
+
|
|
523
|
+
1. **Version Control**: Full Git history for all metadata changes
|
|
524
|
+
2. **Collaboration**: Standard PR workflows for metadata updates
|
|
525
|
+
3. **Tooling**: Use any editor (VS Code, Sublime, etc.)
|
|
526
|
+
4. **Backup**: File-based backups of critical metadata
|
|
527
|
+
5. **Portability**: Easy migration between environments
|
|
528
|
+
6. **Automation**: CI/CD pipeline integration
|
|
529
|
+
7. **Related Data**: Manage parent-child relationships easily
|
|
530
|
+
|
|
531
|
+
## Technical Architecture
|
|
532
|
+
|
|
533
|
+
- Built with Node.js and TypeScript
|
|
534
|
+
- Uses oclif for CLI framework
|
|
535
|
+
- Integrates with MJ Core infrastructure
|
|
536
|
+
- Leverages existing data providers
|
|
537
|
+
- Supports watch mode via chokidar
|
|
538
|
+
- Checksums for change detection
|
|
539
|
+
- Dynamic primary key detection from entity metadata
|
|
540
|
+
- No hardcoded assumptions about entity structure
|
|
541
|
+
- Proper database connection cleanup
|
|
542
|
+
|
|
543
|
+
## Future Enhancements
|
|
544
|
+
|
|
545
|
+
- Plugin system for custom entity handlers
|
|
546
|
+
- Merge conflict resolution UI
|
|
547
|
+
- Bulk operations across entities
|
|
548
|
+
- Metadata validation rules
|
|
549
|
+
- Schema migration support
|
|
550
|
+
- Team collaboration features
|
|
551
|
+
- Bidirectional sync for related entities
|
|
552
|
+
- Custom transformation pipelines
|
package/bin/debug.js
ADDED
package/bin/run
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const oclif = require('@oclif/core')
|
|
4
|
+
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const project = path.join(__dirname, '..', 'tsconfig.json')
|
|
7
|
+
|
|
8
|
+
// In dev mode -> use ts-node and dev plugins
|
|
9
|
+
process.env.NODE_ENV = 'development'
|
|
10
|
+
|
|
11
|
+
require('ts-node').register({project})
|
|
12
|
+
|
|
13
|
+
// In dev mode, always show stack traces
|
|
14
|
+
oclif.settings.debug = true;
|
|
15
|
+
|
|
16
|
+
// Start the CLI
|
|
17
|
+
oclif.run().then(oclif.flush).catch(oclif.Errors.handle)
|
package/bin/run.js
ADDED