eventmodeler 0.3.4 → 0.3.6

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/dist/index.js CHANGED
@@ -48,6 +48,9 @@ function getNamedArg(argList, ...names) {
48
48
  }
49
49
  return undefined;
50
50
  }
51
+ function hasHelpFlag(argList) {
52
+ return argList.includes('-h') || argList.includes('--help');
53
+ }
51
54
  function printHelp() {
52
55
  console.log(`
53
56
  eventmodeler - CLI tool for interacting with Event Model files
@@ -157,6 +160,7 @@ async function main() {
157
160
  let formatArg = null;
158
161
  let chapterArg = null;
159
162
  const filteredArgs = [];
163
+ let helpRequested = false;
160
164
  for (let i = 0; i < args.length; i++) {
161
165
  if (args[i] === '-f' || args[i] === '--file') {
162
166
  fileArg = args[++i];
@@ -167,18 +171,23 @@ async function main() {
167
171
  else if (args[i] === '--chapter') {
168
172
  chapterArg = args[++i];
169
173
  }
170
- else if (args[i] === '-h' || args[i] === '--help') {
171
- printHelp();
172
- process.exit(0);
173
- }
174
174
  else if (args[i] === '-v' || args[i] === '--version') {
175
175
  console.log(`eventmodeler ${VERSION}`);
176
176
  process.exit(0);
177
177
  }
178
+ else if (args[i] === '-h' || args[i] === '--help') {
179
+ helpRequested = true;
180
+ }
178
181
  else {
179
182
  filteredArgs.push(args[i]);
180
183
  }
181
184
  }
185
+ // Handle --help: if no command specified, show general help
186
+ // Otherwise let command-specific help handle it
187
+ if (helpRequested && filteredArgs.length === 0) {
188
+ printHelp();
189
+ process.exit(0);
190
+ }
182
191
  // Determine output format
183
192
  const format = formatArg === 'json' ? 'json'
184
193
  : formatArg === 'xml' ? 'xml'
@@ -195,6 +204,42 @@ async function main() {
195
204
  }
196
205
  // Handle diff and merge commands separately (they manage their own file loading)
197
206
  if (command === 'diff') {
207
+ if (helpRequested) {
208
+ console.log(`
209
+ eventmodeler diff - Compare event model files semantically
210
+
211
+ USAGE:
212
+ eventmodeler diff <file1> <file2> [--format text|xml|json]
213
+ eventmodeler diff <file> [--ref <gitref>] [--format text|xml|json]
214
+ eventmodeler diff --base <file> --compare <file> [--format text|xml|json]
215
+
216
+ ARGUMENTS:
217
+ <file1> <file2> Two files to compare
218
+ <file> Single file to compare against git ref
219
+
220
+ OPTIONS:
221
+ --ref <gitref> Git reference to compare against (default: HEAD)
222
+ --base <file> Base file (alternative syntax)
223
+ --compare <file> Compare file (alternative syntax)
224
+ --format <format> Output format: text (default), xml, or json
225
+
226
+ OUTPUT:
227
+ Semantic differences between models:
228
+ - Added/removed/modified entities
229
+ - Field changes (with flag changes like isGenerated)
230
+ - Flow changes
231
+ - Scenario changes
232
+
233
+ Unlike line-based diff, this understands event model structure.
234
+
235
+ EXAMPLES:
236
+ eventmodeler diff model-v1.eventmodel model-v2.eventmodel
237
+ eventmodeler diff mymodel.eventmodel --ref HEAD~1
238
+ eventmodeler diff mymodel.eventmodel --ref main
239
+ eventmodeler diff model.eventmodel --format json
240
+ `);
241
+ process.exit(0);
242
+ }
198
243
  const baseArg = getNamedArg(filteredArgs, '--base');
199
244
  const compareArg = getNamedArg(filteredArgs, '--compare');
200
245
  const refArg = getNamedArg(filteredArgs, '--ref');
@@ -223,9 +268,49 @@ async function main() {
223
268
  console.error('Usage: eventmodeler diff <file1> <file2>');
224
269
  console.error(' eventmodeler diff <file> [--ref <gitref>]');
225
270
  console.error(' eventmodeler diff --base <file> --compare <file>');
271
+ console.error('Run "eventmodeler diff --help" for more information.');
226
272
  process.exit(1);
227
273
  }
228
274
  if (command === 'merge') {
275
+ if (helpRequested) {
276
+ console.log(`
277
+ eventmodeler merge - Three-way merge of event model files
278
+
279
+ USAGE:
280
+ eventmodeler merge --base <file> --ours <file> --theirs <file> --output <file>
281
+
282
+ OPTIONS:
283
+ --base <file> Common ancestor file (required)
284
+ --ours <file> Our version file (required)
285
+ --theirs <file> Their version file (required)
286
+ --output <file> Output file path (required unless --dry-run)
287
+ --strategy <s> Auto-resolve conflicts: ours or theirs
288
+ --dry-run Show result without writing file
289
+ --format xml|json Output format for conflict reporting
290
+
291
+ HOW IT WORKS:
292
+ Performs semantic three-way merge:
293
+ 1. Identifies changes in "ours" vs base
294
+ 2. Identifies changes in "theirs" vs base
295
+ 3. Auto-merges non-conflicting changes
296
+ 4. Reports conflicts for manual resolution
297
+
298
+ CONFLICT RESOLUTION:
299
+ --strategy ours Keep our changes when conflicts occur
300
+ --strategy theirs Keep their changes when conflicts occur
301
+
302
+ EXAMPLES:
303
+ # Standard merge
304
+ eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel
305
+
306
+ # Auto-resolve with our changes taking precedence
307
+ eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel --strategy ours
308
+
309
+ # Preview merge without writing
310
+ eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --dry-run
311
+ `);
312
+ process.exit(0);
313
+ }
229
314
  const baseArg = getNamedArg(filteredArgs, '--base');
230
315
  const oursArg = getNamedArg(filteredArgs, '--ours');
231
316
  const theirsArg = getNamedArg(filteredArgs, '--theirs');
@@ -237,6 +322,7 @@ async function main() {
237
322
  console.error('Options:');
238
323
  console.error(' --strategy ours|theirs Auto-resolve conflicts');
239
324
  console.error(' --dry-run Show result without writing');
325
+ console.error('Run "eventmodeler merge --help" for more information.');
240
326
  process.exit(1);
241
327
  }
242
328
  if (!outputArg && !dryRun) {
@@ -257,16 +343,80 @@ async function main() {
257
343
  if (command === 'git') {
258
344
  const gitCommand = filteredArgs[1];
259
345
  const globalFlag = filteredArgs.includes('--global');
346
+ if (helpRequested && !gitCommand) {
347
+ console.log(`
348
+ eventmodeler git - Git integration commands
349
+
350
+ USAGE:
351
+ eventmodeler git <command> [options]
352
+
353
+ COMMANDS:
354
+ setup Configure git for semantic diff/merge of .eventmodel files
355
+ status Show current git integration status
356
+
357
+ Run "eventmodeler git <command> --help" for command-specific help.
358
+ `);
359
+ process.exit(0);
360
+ }
260
361
  switch (gitCommand) {
261
362
  case 'setup':
363
+ if (helpRequested) {
364
+ console.log(`
365
+ eventmodeler git setup - Configure git for semantic diff/merge
366
+
367
+ USAGE:
368
+ eventmodeler git setup [--global]
369
+
370
+ OPTIONS:
371
+ --global Configure globally (for all repositories)
372
+
373
+ WHAT IT DOES:
374
+ 1. Adds .gitattributes entry: *.eventmodel diff=eventmodel merge=eventmodel
375
+ 2. Configures git diff driver for semantic comparison
376
+ 3. Configures git merge driver for semantic merging
377
+
378
+ After setup:
379
+ - "git diff" shows semantic differences for .eventmodel files
380
+ - "git merge" performs semantic merging
381
+ - Conflicts are reported at entity level, not line level
382
+
383
+ LOCAL VS GLOBAL:
384
+ Without --global: Configures current repository only
385
+ With --global: Configures for all repositories (user-level)
386
+
387
+ EXAMPLES:
388
+ eventmodeler git setup # Configure current repo
389
+ eventmodeler git setup --global # Configure globally
390
+ `);
391
+ process.exit(0);
392
+ }
262
393
  gitSetup(globalFlag);
263
394
  return;
264
395
  case 'status':
396
+ if (helpRequested) {
397
+ console.log(`
398
+ eventmodeler git status - Show git integration status
399
+
400
+ USAGE:
401
+ eventmodeler git status
402
+
403
+ OUTPUT:
404
+ Shows current configuration:
405
+ - Whether git drivers are configured
406
+ - Local vs global configuration status
407
+ - .gitattributes configuration status
408
+
409
+ EXAMPLES:
410
+ eventmodeler git status
411
+ `);
412
+ process.exit(0);
413
+ }
265
414
  gitStatus();
266
415
  return;
267
416
  default:
268
417
  console.error('Usage: eventmodeler git setup [--global]');
269
418
  console.error(' eventmodeler git status');
419
+ console.error('Run "eventmodeler git --help" for more information.');
270
420
  process.exit(1);
271
421
  }
272
422
  }
@@ -283,82 +433,461 @@ async function main() {
283
433
  const model = loadModel(filePath);
284
434
  switch (command) {
285
435
  case 'list':
436
+ if (helpRequested && !subcommand) {
437
+ console.log(`
438
+ eventmodeler list - List entities in the event model
439
+
440
+ USAGE:
441
+ eventmodeler list <type> [options]
442
+
443
+ TYPES:
444
+ slices List all slices (with optional --chapter filter)
445
+ events List all events
446
+ commands List all commands
447
+ chapters List all chapters
448
+ aggregates List all aggregates
449
+ actors List all actors
450
+
451
+ OPTIONS:
452
+ --chapter <name> Filter slices by chapter (slices only)
453
+ --format xml|json Output format (default: xml)
454
+
455
+ EXAMPLES:
456
+ eventmodeler list slices
457
+ eventmodeler list slices --chapter "Order Management"
458
+ eventmodeler list events --format json
459
+
460
+ Run "eventmodeler list <type> --help" for type-specific help.
461
+ `);
462
+ process.exit(0);
463
+ }
286
464
  switch (subcommand) {
287
465
  case 'slices':
466
+ if (helpRequested) {
467
+ console.log(`
468
+ eventmodeler list slices - List all slices in the event model
469
+
470
+ USAGE:
471
+ eventmodeler list slices [--chapter <name>] [--format xml|json]
472
+
473
+ OPTIONS:
474
+ --chapter <name> Filter by chapter name
475
+ --format <format> Output format: xml (default) or json
476
+
477
+ OUTPUT FIELDS:
478
+ name Slice name
479
+ type state-change | automation | state-view
480
+ status created | in-progress | blocked | done
481
+ chapter Parent chapter name
482
+
483
+ EXAMPLES:
484
+ eventmodeler list slices
485
+ eventmodeler list slices --chapter "Order Management"
486
+ eventmodeler list slices --format json
487
+ `);
488
+ process.exit(0);
489
+ }
288
490
  listSlices(model, format, chapterArg ?? undefined);
289
491
  break;
290
492
  case 'events':
493
+ if (helpRequested) {
494
+ console.log(`
495
+ eventmodeler list events - List all events in the event model
496
+
497
+ USAGE:
498
+ eventmodeler list events [--format xml|json]
499
+
500
+ OPTIONS:
501
+ --format <format> Output format: xml (default) or json
502
+
503
+ OUTPUT FIELDS:
504
+ name Event name
505
+ aggregate Parent aggregate name
506
+
507
+ NOTE: Linked copies (events referencing a canonical original) are excluded.
508
+
509
+ EXAMPLES:
510
+ eventmodeler list events
511
+ eventmodeler list events --format json
512
+ `);
513
+ process.exit(0);
514
+ }
291
515
  listEvents(model, format);
292
516
  break;
293
517
  case 'commands':
518
+ if (helpRequested) {
519
+ console.log(`
520
+ eventmodeler list commands - List all commands in the event model
521
+
522
+ USAGE:
523
+ eventmodeler list commands [--format xml|json]
524
+
525
+ OPTIONS:
526
+ --format <format> Output format: xml (default) or json
527
+
528
+ OUTPUT FIELDS:
529
+ name Command name
530
+ aggregate Parent aggregate name
531
+
532
+ EXAMPLES:
533
+ eventmodeler list commands
534
+ eventmodeler list commands --format json
535
+ `);
536
+ process.exit(0);
537
+ }
294
538
  listCommands(model, format);
295
539
  break;
296
540
  case 'chapters':
541
+ if (helpRequested) {
542
+ console.log(`
543
+ eventmodeler list chapters - List all chapters in the event model
544
+
545
+ USAGE:
546
+ eventmodeler list chapters [--format xml|json]
547
+
548
+ OPTIONS:
549
+ --format <format> Output format: xml (default) or json
550
+
551
+ OUTPUT FIELDS:
552
+ name Chapter name
553
+ sliceCount Number of slices in chapter
554
+
555
+ EXAMPLES:
556
+ eventmodeler list chapters
557
+ eventmodeler list chapters --format json
558
+ `);
559
+ process.exit(0);
560
+ }
297
561
  listChapters(model, format);
298
562
  break;
299
563
  case 'aggregates':
564
+ if (helpRequested) {
565
+ console.log(`
566
+ eventmodeler list aggregates - List all aggregates in the event model
567
+
568
+ USAGE:
569
+ eventmodeler list aggregates [--format xml|json]
570
+
571
+ OPTIONS:
572
+ --format <format> Output format: xml (default) or json
573
+
574
+ OUTPUT FIELDS:
575
+ name Aggregate name
576
+ eventCount Number of events
577
+ commandCount Number of commands
578
+
579
+ EXAMPLES:
580
+ eventmodeler list aggregates
581
+ eventmodeler list aggregates --format json
582
+ `);
583
+ process.exit(0);
584
+ }
300
585
  listAggregates(model, format);
301
586
  break;
302
587
  case 'actors':
588
+ if (helpRequested) {
589
+ console.log(`
590
+ eventmodeler list actors - List all actors in the event model
591
+
592
+ USAGE:
593
+ eventmodeler list actors [--format xml|json]
594
+
595
+ OPTIONS:
596
+ --format <format> Output format: xml (default) or json
597
+
598
+ OUTPUT FIELDS:
599
+ name Actor name
600
+ screenCount Number of screens
601
+
602
+ EXAMPLES:
603
+ eventmodeler list actors
604
+ eventmodeler list actors --format json
605
+ `);
606
+ process.exit(0);
607
+ }
303
608
  listActors(model, format);
304
609
  break;
305
610
  default:
306
611
  console.error(`Unknown list target: ${subcommand}`);
307
612
  console.error('Valid targets: slices, events, commands, chapters, aggregates, actors');
613
+ console.error('Run "eventmodeler list --help" for more information.');
308
614
  process.exit(1);
309
615
  }
310
616
  break;
311
617
  case 'show':
618
+ if (helpRequested && !subcommand) {
619
+ console.log(`
620
+ eventmodeler show - Show detailed information about entities
621
+
622
+ USAGE:
623
+ eventmodeler show <type> <name> [options]
624
+
625
+ TYPES:
626
+ slice Show slice with components and flows
627
+ event Show event with all fields
628
+ command Show command with all fields
629
+ chapter Show chapter with slices and dependencies
630
+ completeness Show field mapping completeness for any element
631
+ model-completeness Show completeness of all flows
632
+ aggregate-completeness Show if events have aggregate ID field
633
+ actor Show actor with screens
634
+
635
+ OPTIONS:
636
+ --format xml|json Output format (default: xml)
637
+
638
+ EXAMPLES:
639
+ eventmodeler show slice "Place Order"
640
+ eventmodeler show event OrderPlaced
641
+ eventmodeler show completeness OrderSummary
642
+
643
+ Run "eventmodeler show <type> --help" for type-specific help.
644
+ `);
645
+ process.exit(0);
646
+ }
312
647
  switch (subcommand) {
313
648
  case 'slice':
649
+ if (helpRequested) {
650
+ console.log(`
651
+ eventmodeler show slice - Show detailed slice information
652
+
653
+ USAGE:
654
+ eventmodeler show slice <name> [--format xml|json]
655
+
656
+ ARGUMENTS:
657
+ <name> Slice name (spaces allowed without quotes)
658
+
659
+ OUTPUT INCLUDES:
660
+ - Slice type (state-change, automation, state-view)
661
+ - Status (created, in-progress, blocked, done)
662
+ - Components: screens, commands, events, read models, processors
663
+ - Each component's fields with types and flags
664
+ - Flow annotations and swimlane positions
665
+ - Inbound/outbound dependencies
666
+ - Scenarios (Given-When-Then specifications)
667
+
668
+ EXAMPLES:
669
+ eventmodeler show slice "Place Order"
670
+ eventmodeler show slice Place Order
671
+ eventmodeler show slice "Place Order" --format json
672
+ `);
673
+ process.exit(0);
674
+ }
314
675
  if (!target) {
315
676
  console.error('Usage: eventmodeler show slice <name>');
677
+ console.error('Run "eventmodeler show slice --help" for more information.');
316
678
  process.exit(1);
317
679
  }
318
680
  showSlice(model, target, format);
319
681
  break;
320
682
  case 'event':
683
+ if (helpRequested) {
684
+ console.log(`
685
+ eventmodeler show event - Show detailed event information
686
+
687
+ USAGE:
688
+ eventmodeler show event <name> [--format xml|json]
689
+
690
+ ARGUMENTS:
691
+ <name> Event name (spaces allowed without quotes)
692
+
693
+ OUTPUT INCLUDES:
694
+ - Event name and aggregate
695
+ - All fields with:
696
+ - name: Field name
697
+ - type: UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
698
+ - isList: Whether field is an array
699
+ - isOptional: Whether field can be null
700
+ - isGenerated: Whether field is computed (not mapped from source)
701
+ - subfields: Nested fields for Custom types (recursive, with all flags)
702
+
703
+ FIELD OUTPUT FORMAT (XML):
704
+ <field name="orderId" type="UUID"/>
705
+ <field name="total" type="Decimal" isGenerated="true"/>
706
+ <field name="items" type="Custom" isList="true">
707
+ <field name="productId" type="UUID"/>
708
+ <field name="lineTotal" type="Decimal" isGenerated="true"/>
709
+ </field>
710
+
711
+ EXAMPLES:
712
+ eventmodeler show event OrderPlaced
713
+ eventmodeler show event "Order Placed" --format json
714
+ `);
715
+ process.exit(0);
716
+ }
321
717
  if (!target) {
322
718
  console.error('Usage: eventmodeler show event <name>');
719
+ console.error('Run "eventmodeler show event --help" for more information.');
323
720
  process.exit(1);
324
721
  }
325
722
  showEvent(model, target, format);
326
723
  break;
327
724
  case 'command':
725
+ if (helpRequested) {
726
+ console.log(`
727
+ eventmodeler show command - Show detailed command information
728
+
729
+ USAGE:
730
+ eventmodeler show command <name> [--format xml|json]
731
+
732
+ ARGUMENTS:
733
+ <name> Command name (spaces allowed without quotes)
734
+
735
+ OUTPUT INCLUDES:
736
+ - Command name and aggregate
737
+ - All fields with types, flags, and nested subfields
738
+
739
+ EXAMPLES:
740
+ eventmodeler show command PlaceOrder
741
+ eventmodeler show command "Place Order" --format json
742
+ `);
743
+ process.exit(0);
744
+ }
328
745
  if (!target) {
329
746
  console.error('Usage: eventmodeler show command <name>');
747
+ console.error('Run "eventmodeler show command --help" for more information.');
330
748
  process.exit(1);
331
749
  }
332
750
  showCommand(model, target, format);
333
751
  break;
334
752
  case 'chapter':
753
+ if (helpRequested) {
754
+ console.log(`
755
+ eventmodeler show chapter - Show detailed chapter information
756
+
757
+ USAGE:
758
+ eventmodeler show chapter <name> [--format xml|json]
759
+
760
+ ARGUMENTS:
761
+ <name> Chapter name
762
+
763
+ OUTPUT INCLUDES:
764
+ - All slices in the chapter
765
+ - Flow graph showing internal dependencies
766
+ - External dependencies (inbound/outbound)
767
+
768
+ EXAMPLES:
769
+ eventmodeler show chapter "Order Management"
770
+ eventmodeler show chapter "Order Management" --format json
771
+ `);
772
+ process.exit(0);
773
+ }
335
774
  if (!target) {
336
775
  console.error('Usage: eventmodeler show chapter <name>');
776
+ console.error('Run "eventmodeler show chapter --help" for more information.');
337
777
  process.exit(1);
338
778
  }
339
779
  showChapter(model, target, format);
340
780
  break;
341
781
  case 'completeness':
782
+ if (helpRequested) {
783
+ console.log(`
784
+ eventmodeler show completeness - Show field mapping completeness
785
+
786
+ USAGE:
787
+ eventmodeler show completeness <name> [--format xml|json]
788
+
789
+ ARGUMENTS:
790
+ <name> Element name (command, event, read model, screen, or processor)
791
+
792
+ OUTPUT INCLUDES:
793
+ - Total fields vs mapped fields
794
+ - List of unmapped fields needing attention
795
+ - Mapping sources for mapped fields
796
+
797
+ IMPORTANT - GENERATED FIELDS:
798
+ Fields with isGenerated=true are EXCLUDED from completeness checks.
799
+ Generated fields are computed/synthesized values that don't need
800
+ source mappings (e.g., calculated totals, timestamps, derived data).
801
+
802
+ EXAMPLES:
803
+ eventmodeler show completeness OrderSummary
804
+ eventmodeler show completeness "Order Summary" --format json
805
+ `);
806
+ process.exit(0);
807
+ }
342
808
  if (!target) {
343
809
  console.error('Usage: eventmodeler show completeness <element-name>');
344
810
  console.error('Searches: commands, events, read models, screens, processors');
811
+ console.error('Run "eventmodeler show completeness --help" for more information.');
345
812
  process.exit(1);
346
813
  }
347
814
  showCompleteness(model, target, format);
348
815
  break;
349
816
  case 'model-completeness':
817
+ if (helpRequested) {
818
+ console.log(`
819
+ eventmodeler show model-completeness - Show completeness of all flows
820
+
821
+ USAGE:
822
+ eventmodeler show model-completeness [--format xml|json]
823
+
824
+ OUTPUT INCLUDES:
825
+ - Complete flows (all required fields mapped)
826
+ - Incomplete flows with missing mappings
827
+ - Overall completeness percentage
828
+
829
+ NOTE: Generated fields (isGenerated=true) are excluded from checks.
830
+
831
+ EXAMPLES:
832
+ eventmodeler show model-completeness
833
+ eventmodeler show model-completeness --format json
834
+ `);
835
+ process.exit(0);
836
+ }
350
837
  showModelCompleteness(model, format);
351
838
  break;
352
839
  case 'aggregate-completeness':
840
+ if (helpRequested) {
841
+ console.log(`
842
+ eventmodeler show aggregate-completeness - Check aggregate ID field presence
843
+
844
+ USAGE:
845
+ eventmodeler show aggregate-completeness <name> [--format xml|json]
846
+
847
+ ARGUMENTS:
848
+ <name> Aggregate name
849
+
850
+ OUTPUT:
851
+ Lists all events in the aggregate and whether each has the
852
+ aggregate ID field (e.g., "orderId" for "Order" aggregate).
853
+
854
+ EXAMPLES:
855
+ eventmodeler show aggregate-completeness Order
856
+ eventmodeler show aggregate-completeness "Order" --format json
857
+ `);
858
+ process.exit(0);
859
+ }
353
860
  if (!target) {
354
861
  console.error('Usage: eventmodeler show aggregate-completeness <aggregate-name>');
862
+ console.error('Run "eventmodeler show aggregate-completeness --help" for more information.');
355
863
  process.exit(1);
356
864
  }
357
865
  showAggregateCompleteness(model, target, format);
358
866
  break;
359
867
  case 'actor':
868
+ if (helpRequested) {
869
+ console.log(`
870
+ eventmodeler show actor - Show detailed actor information
871
+
872
+ USAGE:
873
+ eventmodeler show actor <name> [--format xml|json]
874
+
875
+ ARGUMENTS:
876
+ <name> Actor name
877
+
878
+ OUTPUT INCLUDES:
879
+ - Actor name
880
+ - All associated screens
881
+
882
+ EXAMPLES:
883
+ eventmodeler show actor Customer
884
+ eventmodeler show actor "Admin User" --format json
885
+ `);
886
+ process.exit(0);
887
+ }
360
888
  if (!target) {
361
889
  console.error('Usage: eventmodeler show actor <actor-name>');
890
+ console.error('Run "eventmodeler show actor --help" for more information.');
362
891
  process.exit(1);
363
892
  }
364
893
  showActor(model, target, format);
@@ -366,17 +895,73 @@ async function main() {
366
895
  default:
367
896
  console.error(`Unknown show target: ${subcommand}`);
368
897
  console.error('Valid targets: slice, event, command, chapter, completeness, model-completeness, aggregate-completeness, actor');
898
+ console.error('Run "eventmodeler show --help" for more information.');
369
899
  process.exit(1);
370
900
  }
371
901
  break;
372
902
  case 'search':
903
+ if (helpRequested) {
904
+ console.log(`
905
+ eventmodeler search - Search for entities by name
906
+
907
+ USAGE:
908
+ eventmodeler search <term> [--format xml|json]
909
+
910
+ ARGUMENTS:
911
+ <term> Search term (case-insensitive partial match)
912
+
913
+ OPTIONS:
914
+ --format <format> Output format: xml (default) or json
915
+
916
+ SEARCHES ACROSS:
917
+ - Slices
918
+ - Events
919
+ - Commands
920
+ - Read Models
921
+ - Screens
922
+ - Processors
923
+ - Chapters
924
+ - Aggregates
925
+ - Actors
926
+
927
+ EXAMPLES:
928
+ eventmodeler search order
929
+ eventmodeler search "payment" --format json
930
+ `);
931
+ process.exit(0);
932
+ }
373
933
  if (!subcommand) {
374
934
  console.error('Usage: eventmodeler search <term>');
935
+ console.error('Run "eventmodeler search --help" for more information.');
375
936
  process.exit(1);
376
937
  }
377
938
  search(model, subcommand, format);
378
939
  break;
379
940
  case 'mark': {
941
+ if (helpRequested) {
942
+ console.log(`
943
+ eventmodeler mark - Mark a slice's status
944
+
945
+ USAGE:
946
+ eventmodeler mark <slice-name> <status>
947
+
948
+ ARGUMENTS:
949
+ <slice-name> Slice name (can include spaces)
950
+ <status> One of: created, in-progress, blocked, done
951
+
952
+ STATUSES:
953
+ created Initial state, not yet started
954
+ in-progress Currently being worked on
955
+ blocked Work paused due to dependency or issue
956
+ done Completed
957
+
958
+ EXAMPLES:
959
+ eventmodeler mark "Place Order" done
960
+ eventmodeler mark "Process Payment" in-progress
961
+ eventmodeler mark "Ship Order" blocked
962
+ `);
963
+ process.exit(0);
964
+ }
380
965
  // mark <slice-name> <status> - status is last arg, slice name is everything before
381
966
  // Note: subcommand contains first part of slice name, remainingArgs has the rest
382
967
  const validStatuses = ['created', 'in-progress', 'blocked', 'done'];
@@ -385,6 +970,7 @@ async function main() {
385
970
  if (allArgs.length < 2 || !validStatuses.includes(lastArg)) {
386
971
  console.error('Usage: eventmodeler mark <slice-name> <status>');
387
972
  console.error('Valid statuses: created, in-progress, blocked, done');
973
+ console.error('Run "eventmodeler mark --help" for more information.');
388
974
  process.exit(1);
389
975
  }
390
976
  const sliceName = allArgs.slice(0, -1).join(' ');
@@ -393,22 +979,145 @@ async function main() {
393
979
  break;
394
980
  }
395
981
  case 'summary':
982
+ if (helpRequested) {
983
+ console.log(`
984
+ eventmodeler summary - Show model summary statistics
985
+
986
+ USAGE:
987
+ eventmodeler summary [--format xml|json]
988
+
989
+ OPTIONS:
990
+ --format <format> Output format: xml (default) or json
991
+
992
+ OUTPUT:
993
+ Aggregate statistics including:
994
+ - Total counts (slices, events, commands, read models, screens, etc.)
995
+ - Slices by type (state-change, automation, state-view)
996
+ - Slices by status (created, in-progress, blocked, done)
997
+ - Chapter summary
998
+
999
+ EXAMPLES:
1000
+ eventmodeler summary
1001
+ eventmodeler summary --format json
1002
+ `);
1003
+ process.exit(0);
1004
+ }
396
1005
  showModelSummary(model, format);
397
1006
  break;
398
1007
  case 'export':
1008
+ if (helpRequested && !subcommand) {
1009
+ console.log(`
1010
+ eventmodeler export - Export the model
1011
+
1012
+ USAGE:
1013
+ eventmodeler export <format>
1014
+
1015
+ FORMATS:
1016
+ json Export entire model as JSON
1017
+
1018
+ Run "eventmodeler export json --help" for detailed help.
1019
+ `);
1020
+ process.exit(0);
1021
+ }
399
1022
  switch (subcommand) {
400
1023
  case 'json':
1024
+ if (helpRequested) {
1025
+ console.log(`
1026
+ eventmodeler export json - Export entire model as JSON
1027
+
1028
+ USAGE:
1029
+ eventmodeler export json
1030
+
1031
+ OUTPUT:
1032
+ Complete event model as JSON to stdout, including:
1033
+ - All entities (slices, events, commands, read models, screens, etc.)
1034
+ - All flows and field mappings
1035
+ - All scenarios
1036
+ - Metadata (chapters, aggregates, actors)
1037
+
1038
+ EXAMPLES:
1039
+ eventmodeler export json
1040
+ eventmodeler export json > model.json
1041
+ eventmodeler export json | jq '.events'
1042
+ `);
1043
+ process.exit(0);
1044
+ }
401
1045
  exportEventmodelToJson(model);
402
1046
  break;
403
1047
  default:
404
1048
  console.error(`Unknown export format: ${subcommand}`);
405
1049
  console.error('Valid formats: json');
1050
+ console.error('Run "eventmodeler export --help" for more information.');
406
1051
  process.exit(1);
407
1052
  }
408
1053
  break;
409
1054
  case 'add':
1055
+ if (helpRequested && !subcommand) {
1056
+ console.log(`
1057
+ eventmodeler add - Add entities to the model
1058
+
1059
+ USAGE:
1060
+ eventmodeler add <type> [options]
1061
+
1062
+ TYPES:
1063
+ scenario Add Given-When-Then scenario to a slice
1064
+ field Add field to command, event, read model, screen, or processor
1065
+
1066
+ Run "eventmodeler add <type> --help" for type-specific help.
1067
+ `);
1068
+ process.exit(0);
1069
+ }
410
1070
  switch (subcommand) {
411
1071
  case 'scenario': {
1072
+ if (helpRequested) {
1073
+ console.log(`
1074
+ eventmodeler add scenario - Add a scenario to a slice
1075
+
1076
+ USAGE:
1077
+ eventmodeler add scenario --slice <name> --json|--xml <data>
1078
+
1079
+ OPTIONS:
1080
+ --slice <name> Target slice name (required)
1081
+ --json <data> Scenario in JSON format
1082
+ --xml <data> Scenario in XML format
1083
+
1084
+ JSON FORMAT:
1085
+ {
1086
+ "name": "Scenario name",
1087
+ "given": { // Optional: preconditions
1088
+ "type": "events",
1089
+ "events": ["EventName1", "EventName2"]
1090
+ },
1091
+ "when": { // Optional: trigger
1092
+ "type": "command",
1093
+ "command": "CommandName"
1094
+ },
1095
+ "then": { // Required: expected outcome
1096
+ "type": "events",
1097
+ "events": ["ExpectedEvent"]
1098
+ }
1099
+ }
1100
+
1101
+ XML FORMAT:
1102
+ <scenario name="Scenario name">
1103
+ <given type="events">
1104
+ <event>EventName1</event>
1105
+ </given>
1106
+ <when type="command">
1107
+ <command>CommandName</command>
1108
+ </when>
1109
+ <then type="events">
1110
+ <event>ExpectedEvent</event>
1111
+ </then>
1112
+ </scenario>
1113
+
1114
+ EXAMPLES:
1115
+ eventmodeler add scenario --slice "Place Order" --json '{"name": "Happy path", "then": {"type": "events", "events": ["OrderPlaced"]}}'
1116
+
1117
+ eventmodeler add scenario --slice "Place Order" --xml '<scenario name="Out of stock"><given type="events"><event>ProductOutOfStock</event></given><then type="events"><event>OrderRejected</event></then></scenario>'
1118
+ `);
1119
+ process.exit(0);
1120
+ }
412
1121
  const sliceArg = getNamedArg(filteredArgs, '--slice');
413
1122
  const jsonArg = getNamedArg(filteredArgs, '--json');
414
1123
  const xmlArg = getNamedArg(filteredArgs, '--xml');
@@ -416,17 +1125,114 @@ async function main() {
416
1125
  if (!sliceArg) {
417
1126
  console.error('Error: --slice is required');
418
1127
  console.error('Usage: eventmodeler add scenario --slice <name> --json|--xml <data>');
1128
+ console.error('Run "eventmodeler add scenario --help" for detailed format.');
419
1129
  process.exit(1);
420
1130
  }
421
1131
  if (!inputData) {
422
1132
  console.error('Error: --json or --xml is required');
423
1133
  console.error('Usage: eventmodeler add scenario --slice <name> --json|--xml <data>');
1134
+ console.error('Run "eventmodeler add scenario --help" for detailed format.');
424
1135
  process.exit(1);
425
1136
  }
426
1137
  addScenario(model, filePath, sliceArg, inputData);
427
1138
  break;
428
1139
  }
429
1140
  case 'field': {
1141
+ if (helpRequested) {
1142
+ console.log(`
1143
+ eventmodeler add field - Add a field to an entity
1144
+
1145
+ USAGE:
1146
+ eventmodeler add field --command|--event|--read-model|--screen|--processor <name> --json|--xml <data>
1147
+
1148
+ OPTIONS:
1149
+ --command <name> Target command name
1150
+ --event <name> Target event name
1151
+ --read-model <name> Target read model name
1152
+ --screen <name> Target screen name
1153
+ --processor <name> Target processor name
1154
+ --json <data> Field definition in JSON format
1155
+ --xml <data> Field definition in XML format
1156
+
1157
+ FIELD TYPES:
1158
+ UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
1159
+
1160
+ FIELD FLAGS (work on ALL fields including nested subfields):
1161
+ isList - Field contains multiple values (array)
1162
+ isOptional - Field may be null/missing
1163
+ isGenerated - Field is computed/synthesized, not mapped from source
1164
+ isUserInput - (Screen only) Field is entered by user
1165
+
1166
+ JSON FORMAT:
1167
+ Simple field:
1168
+ {"name": "orderId", "type": "UUID"}
1169
+
1170
+ Field with flags:
1171
+ {"name": "notes", "type": "String", "isOptional": true}
1172
+ {"name": "tags", "type": "String", "isList": true}
1173
+ {"name": "total", "type": "Decimal", "isGenerated": true}
1174
+
1175
+ Nested Custom field with subfields (ALL flags work on subfields):
1176
+ {
1177
+ "name": "lineItem",
1178
+ "type": "Custom",
1179
+ "subfields": [
1180
+ {"name": "productId", "type": "UUID"},
1181
+ {"name": "quantity", "type": "Int"},
1182
+ {"name": "unitPrice", "type": "Decimal"},
1183
+ {"name": "lineTotal", "type": "Decimal", "isGenerated": true}
1184
+ ]
1185
+ }
1186
+
1187
+ List of Custom with generated subfields:
1188
+ {
1189
+ "name": "items",
1190
+ "type": "Custom",
1191
+ "isList": true,
1192
+ "subfields": [
1193
+ {"name": "sku", "type": "String"},
1194
+ {"name": "qty", "type": "Int"},
1195
+ {"name": "calculatedPrice", "type": "Decimal", "isGenerated": true}
1196
+ ]
1197
+ }
1198
+
1199
+ XML FORMAT:
1200
+ Simple field:
1201
+ <field name="orderId" type="UUID"/>
1202
+
1203
+ Field with flags:
1204
+ <field name="notes" type="String" isOptional="true"/>
1205
+ <field name="tags" type="String" isList="true"/>
1206
+ <field name="total" type="Decimal" isGenerated="true"/>
1207
+
1208
+ Nested Custom field (ALL flags work on subfields):
1209
+ <field name="lineItem" type="Custom">
1210
+ <field name="productId" type="UUID"/>
1211
+ <field name="quantity" type="Int"/>
1212
+ <field name="unitPrice" type="Decimal"/>
1213
+ <field name="lineTotal" type="Decimal" isGenerated="true"/>
1214
+ </field>
1215
+
1216
+ List of Custom with flags on subfields:
1217
+ <field name="items" type="Custom" isList="true">
1218
+ <field name="sku" type="String"/>
1219
+ <field name="qty" type="Int"/>
1220
+ <field name="calculatedPrice" type="Decimal" isGenerated="true"/>
1221
+ <field name="notes" type="String" isOptional="true"/>
1222
+ </field>
1223
+
1224
+ NOTES:
1225
+ - Generated fields are excluded from completeness checks
1226
+ - Custom type fields must have subfields defined
1227
+ - Subfields support arbitrary nesting depth
1228
+
1229
+ EXAMPLES:
1230
+ eventmodeler add field --event OrderPlaced --json '{"name": "orderId", "type": "UUID"}'
1231
+ eventmodeler add field --read-model OrderSummary --json '{"name": "totalWithTax", "type": "Decimal", "isGenerated": true}'
1232
+ eventmodeler add field --event OrderPlaced --xml '<field name="item" type="Custom"><field name="price" type="Decimal"/><field name="tax" type="Decimal" isGenerated="true"/></field>'
1233
+ `);
1234
+ process.exit(0);
1235
+ }
430
1236
  const commandArg = getNamedArg(filteredArgs, '--command');
431
1237
  const eventArg = getNamedArg(filteredArgs, '--event');
432
1238
  const readModelArg = getNamedArg(filteredArgs, '--read-model');
@@ -438,6 +1244,7 @@ async function main() {
438
1244
  if (!inputData) {
439
1245
  console.error('Error: --json or --xml is required');
440
1246
  console.error('Usage: eventmodeler add field --command|--event|--read-model|--screen|--processor <name> --json|--xml <data>');
1247
+ console.error('Run "eventmodeler add field --help" for detailed format documentation.');
441
1248
  process.exit(1);
442
1249
  }
443
1250
  addField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, inputData);
@@ -450,18 +1257,74 @@ async function main() {
450
1257
  }
451
1258
  break;
452
1259
  case 'remove':
1260
+ if (helpRequested && !subcommand) {
1261
+ console.log(`
1262
+ eventmodeler remove - Remove entities from the model
1263
+
1264
+ USAGE:
1265
+ eventmodeler remove <type> [options]
1266
+
1267
+ TYPES:
1268
+ scenario Remove a scenario from a slice
1269
+ field Remove a field from an entity
1270
+
1271
+ Run "eventmodeler remove <type> --help" for type-specific help.
1272
+ `);
1273
+ process.exit(0);
1274
+ }
453
1275
  switch (subcommand) {
454
1276
  case 'scenario': {
1277
+ if (helpRequested) {
1278
+ console.log(`
1279
+ eventmodeler remove scenario - Remove a scenario from a slice
1280
+
1281
+ USAGE:
1282
+ eventmodeler remove scenario <name> [--slice <slice-name>]
1283
+
1284
+ ARGUMENTS:
1285
+ <name> Scenario name to remove
1286
+
1287
+ OPTIONS:
1288
+ --slice <name> Limit search to specific slice (optional)
1289
+
1290
+ EXAMPLES:
1291
+ eventmodeler remove scenario "Happy path"
1292
+ eventmodeler remove scenario "Edge case" --slice "Place Order"
1293
+ `);
1294
+ process.exit(0);
1295
+ }
455
1296
  const scenarioName = target;
456
1297
  const sliceArg = getNamedArg(filteredArgs, '--slice');
457
1298
  if (!scenarioName) {
458
1299
  console.error('Usage: eventmodeler remove scenario <name> [--slice <slice-name>]');
1300
+ console.error('Run "eventmodeler remove scenario --help" for more information.');
459
1301
  process.exit(1);
460
1302
  }
461
1303
  removeScenario(model, filePath, scenarioName, sliceArg);
462
1304
  break;
463
1305
  }
464
1306
  case 'field': {
1307
+ if (helpRequested) {
1308
+ console.log(`
1309
+ eventmodeler remove field - Remove a field from an entity
1310
+
1311
+ USAGE:
1312
+ eventmodeler remove field --command|--event|--read-model|--screen|--processor <name> --field <field-name>
1313
+
1314
+ OPTIONS:
1315
+ --command <name> Target command name
1316
+ --event <name> Target event name
1317
+ --read-model <name> Target read model name
1318
+ --screen <name> Target screen name
1319
+ --processor <name> Target processor name
1320
+ --field <name> Field name to remove (required)
1321
+
1322
+ EXAMPLES:
1323
+ eventmodeler remove field --event OrderPlaced --field orderId
1324
+ eventmodeler remove field --read-model "Order Summary" --field notes
1325
+ `);
1326
+ process.exit(0);
1327
+ }
465
1328
  const commandArg = getNamedArg(filteredArgs, '--command');
466
1329
  const eventArg = getNamedArg(filteredArgs, '--event');
467
1330
  const readModelArg = getNamedArg(filteredArgs, '--read-model');
@@ -471,6 +1334,7 @@ async function main() {
471
1334
  if (!fieldArg) {
472
1335
  console.error('Error: --field is required');
473
1336
  console.error('Usage: eventmodeler remove field --command|--event|--read-model|--screen|--processor <name> --field <field-name>');
1337
+ console.error('Run "eventmodeler remove field --help" for more information.');
474
1338
  process.exit(1);
475
1339
  }
476
1340
  removeField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, fieldArg);
@@ -479,12 +1343,63 @@ async function main() {
479
1343
  default:
480
1344
  console.error(`Unknown remove target: ${subcommand}`);
481
1345
  console.error('Valid targets: scenario, field');
1346
+ console.error('Run "eventmodeler remove --help" for more information.');
482
1347
  process.exit(1);
483
1348
  }
484
1349
  break;
485
1350
  case 'map':
1351
+ if (helpRequested && !subcommand) {
1352
+ console.log(`
1353
+ eventmodeler map - Set field mappings
1354
+
1355
+ USAGE:
1356
+ eventmodeler map <type> [options]
1357
+
1358
+ TYPES:
1359
+ fields Set field mappings on a flow
1360
+
1361
+ Run "eventmodeler map fields --help" for detailed help.
1362
+ `);
1363
+ process.exit(0);
1364
+ }
486
1365
  switch (subcommand) {
487
1366
  case 'fields': {
1367
+ if (helpRequested) {
1368
+ console.log(`
1369
+ eventmodeler map fields - Set field mappings on a flow
1370
+
1371
+ USAGE:
1372
+ eventmodeler map fields --flow <source→target> --json|--xml <mappings>
1373
+
1374
+ OPTIONS:
1375
+ --flow <spec> Flow as "SourceName→TargetName" (use → or ->)
1376
+ --json <data> Mappings in JSON format
1377
+ --xml <data> Mappings in XML format
1378
+
1379
+ JSON FORMAT:
1380
+ [
1381
+ {"from": "sourceField", "to": "targetField"},
1382
+ {"from": "amount", "to": "orderTotal"}
1383
+ ]
1384
+
1385
+ XML FORMAT:
1386
+ <mappings>
1387
+ <mapping from="sourceField" to="targetField"/>
1388
+ <mapping from="amount" to="orderTotal"/>
1389
+ </mappings>
1390
+
1391
+ NOTES:
1392
+ - Mappings define how fields flow from source to target
1393
+ - Fields marked as isGenerated=true don't need mappings
1394
+ - Use "show completeness" to check mapping status
1395
+
1396
+ EXAMPLES:
1397
+ eventmodeler map fields --flow "OrderPlaced→OrderSummary" --json '[{"from": "total", "to": "totalAmount"}]'
1398
+
1399
+ eventmodeler map fields --flow "OrderPlaced->OrderSummary" --xml '<mappings><mapping from="total" to="totalAmount"/></mappings>'
1400
+ `);
1401
+ process.exit(0);
1402
+ }
488
1403
  const flowArg = getNamedArg(filteredArgs, '--flow');
489
1404
  const jsonArg = getNamedArg(filteredArgs, '--json');
490
1405
  const xmlArg = getNamedArg(filteredArgs, '--xml');
@@ -492,11 +1407,13 @@ async function main() {
492
1407
  if (!flowArg) {
493
1408
  console.error('Error: --flow is required');
494
1409
  console.error('Usage: eventmodeler map fields --flow <source→target> --json|--xml <mappings>');
1410
+ console.error('Run "eventmodeler map fields --help" for detailed format.');
495
1411
  process.exit(1);
496
1412
  }
497
1413
  if (!inputData) {
498
1414
  console.error('Error: --json or --xml is required');
499
1415
  console.error('Usage: eventmodeler map fields --flow <source→target> --json|--xml <mappings>');
1416
+ console.error('Run "eventmodeler map fields --help" for detailed format.');
500
1417
  process.exit(1);
501
1418
  }
502
1419
  mapFields(model, filePath, flowArg, inputData);
@@ -505,12 +1422,70 @@ async function main() {
505
1422
  default:
506
1423
  console.error(`Unknown map target: ${subcommand}`);
507
1424
  console.error('Valid targets: fields');
1425
+ console.error('Run "eventmodeler map --help" for more information.');
508
1426
  process.exit(1);
509
1427
  }
510
1428
  break;
511
1429
  case 'update':
1430
+ if (helpRequested && !subcommand) {
1431
+ console.log(`
1432
+ eventmodeler update - Update entities in the model
1433
+
1434
+ USAGE:
1435
+ eventmodeler update <type> [options]
1436
+
1437
+ TYPES:
1438
+ field Update field properties
1439
+
1440
+ Run "eventmodeler update field --help" for detailed help.
1441
+ `);
1442
+ process.exit(0);
1443
+ }
512
1444
  switch (subcommand) {
513
1445
  case 'field': {
1446
+ if (helpRequested) {
1447
+ console.log(`
1448
+ eventmodeler update field - Update field properties
1449
+
1450
+ USAGE:
1451
+ eventmodeler update field --command|--event|--read-model|--screen|--processor <name> --field <field-name> [updates]
1452
+
1453
+ TARGET OPTIONS (one required):
1454
+ --command <name> Target command
1455
+ --event <name> Target event
1456
+ --read-model <name> Target read model
1457
+ --screen <name> Target screen
1458
+ --processor <name> Target processor
1459
+
1460
+ REQUIRED:
1461
+ --field <name> Field to update
1462
+
1463
+ UPDATE OPTIONS (at least one required):
1464
+ --optional true|false Set isOptional flag
1465
+ --generated true|false Set isGenerated flag
1466
+ --user-input true|false Set isUserInput flag (screen only)
1467
+ --type <type> Change field type
1468
+
1469
+ FIELD FLAGS EXPLAINED:
1470
+ isOptional Field may be null/missing
1471
+ isGenerated Field is computed, excluded from completeness checks
1472
+ isUserInput (Screen only) Field entered by user vs displayed
1473
+
1474
+ EXAMPLES:
1475
+ # Mark field as optional
1476
+ eventmodeler update field --read-model OrderSummary --field notes --optional true
1477
+
1478
+ # Mark field as generated (computed value, no mapping needed)
1479
+ eventmodeler update field --read-model OrderSummary --field totalWithTax --generated true
1480
+
1481
+ # Mark screen field as user input
1482
+ eventmodeler update field --screen "Order Form" --field quantity --user-input true
1483
+
1484
+ # Change field type
1485
+ eventmodeler update field --event OrderPlaced --field amount --type Decimal
1486
+ `);
1487
+ process.exit(0);
1488
+ }
514
1489
  const commandArg = getNamedArg(filteredArgs, '--command');
515
1490
  const eventArg = getNamedArg(filteredArgs, '--event');
516
1491
  const readModelArg = getNamedArg(filteredArgs, '--read-model');
@@ -524,6 +1499,7 @@ async function main() {
524
1499
  if (!fieldArg) {
525
1500
  console.error('Error: --field is required');
526
1501
  console.error('Usage: eventmodeler update field --command|--event|--read-model|--screen|--processor <name> --field <field-name> [--optional true|false] [--generated true|false] [--user-input true|false (screen only)]');
1502
+ console.error('Run "eventmodeler update field --help" for detailed options.');
527
1503
  process.exit(1);
528
1504
  }
529
1505
  // --user-input is only valid for screens
@@ -546,6 +1522,7 @@ async function main() {
546
1522
  }
547
1523
  if (Object.keys(updates).length === 0) {
548
1524
  console.error('Error: Must specify at least one update (--optional, --generated, --user-input, or --type)');
1525
+ console.error('Run "eventmodeler update field --help" for available options.');
549
1526
  process.exit(1);
550
1527
  }
551
1528
  updateField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, fieldArg, updates);
@@ -554,48 +1531,294 @@ async function main() {
554
1531
  default:
555
1532
  console.error(`Unknown update target: ${subcommand}`);
556
1533
  console.error('Valid targets: field');
1534
+ console.error('Run "eventmodeler update --help" for more information.');
557
1535
  process.exit(1);
558
1536
  }
559
1537
  break;
560
1538
  case 'create':
1539
+ if (helpRequested && !subcommand) {
1540
+ console.log(`
1541
+ eventmodeler create - Create new slices and flows
1542
+
1543
+ USAGE:
1544
+ eventmodeler create <type> [options]
1545
+
1546
+ TYPES:
1547
+ state-change-slice Create Screen → Command → Event slice
1548
+ automation-slice Create ReadModel → Processor → Command → Event slice
1549
+ state-view-slice Create ReadModel-only slice
1550
+ flow Create flow between elements
1551
+
1552
+ Run "eventmodeler create <type> --help" for type-specific help.
1553
+ `);
1554
+ process.exit(0);
1555
+ }
561
1556
  switch (subcommand) {
562
1557
  case 'state-change-slice': {
1558
+ if (helpRequested) {
1559
+ console.log(`
1560
+ eventmodeler create state-change-slice - Create a state-change slice
1561
+
1562
+ A state-change slice represents user action: Screen → Command → Event
1563
+
1564
+ USAGE:
1565
+ eventmodeler create state-change-slice --xml <data>
1566
+
1567
+ XML FORMAT:
1568
+ <state-change-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
1569
+ <screen name="Screen Name" actor="Actor Name">
1570
+ <field name="fieldName" type="Type" [flags]/>
1571
+ </screen>
1572
+ <command name="CommandName">
1573
+ <field name="fieldName" type="Type" [flags]/>
1574
+ </command>
1575
+ <event name="EventName">
1576
+ <field name="fieldName" type="Type" [flags]/>
1577
+ </event>
1578
+ </state-change-slice>
1579
+
1580
+ POSITIONING (IMPORTANT):
1581
+ after="Slice Name" Place this slice immediately after the named slice
1582
+ before="Slice Name" Place this slice immediately before the named slice
1583
+ (shifts existing slices to the right)
1584
+
1585
+ If neither is specified, the slice is placed at the rightmost position.
1586
+ Use "eventmodeler list slices" to see existing slice names for positioning.
1587
+
1588
+ FIELD TYPES:
1589
+ UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
1590
+
1591
+ FIELD FLAGS (work on ALL fields and nested subfields):
1592
+ isList="true" Array/list of values
1593
+ isOptional="true" Nullable field
1594
+ isGenerated="true" Computed field (excluded from mapping completeness)
1595
+ isUserInput="true" User-entered field (screen fields only)
1596
+
1597
+ NESTED CUSTOM FIELDS:
1598
+ <field name="address" type="Custom">
1599
+ <field name="street" type="String"/>
1600
+ <field name="city" type="String"/>
1601
+ <field name="formattedFull" type="String" isGenerated="true"/>
1602
+ </field>
1603
+
1604
+ EXAMPLES:
1605
+ # Create slice at the end (default)
1606
+ eventmodeler create state-change-slice --xml '
1607
+ <state-change-slice name="Place Order">
1608
+ <screen name="Order Form" actor="Customer">
1609
+ <field name="productId" type="UUID" isUserInput="true"/>
1610
+ </screen>
1611
+ <command name="PlaceOrder">
1612
+ <field name="productId" type="UUID"/>
1613
+ </command>
1614
+ <event name="OrderPlaced">
1615
+ <field name="orderId" type="UUID"/>
1616
+ <field name="productId" type="UUID"/>
1617
+ </event>
1618
+ </state-change-slice>'
1619
+
1620
+ # Create slice after an existing slice
1621
+ eventmodeler create state-change-slice --xml '
1622
+ <state-change-slice name="Confirm Order" after="Place Order">
1623
+ ...
1624
+ </state-change-slice>'
1625
+
1626
+ # Create slice before an existing slice (shifts others right)
1627
+ eventmodeler create state-change-slice --xml '
1628
+ <state-change-slice name="Review Cart" before="Place Order">
1629
+ ...
1630
+ </state-change-slice>'
1631
+ `);
1632
+ process.exit(0);
1633
+ }
563
1634
  const xmlArg = getNamedArg(filteredArgs, '--xml');
564
1635
  if (!xmlArg) {
565
1636
  console.error('Error: --xml is required');
566
1637
  console.error('Usage: eventmodeler create state-change-slice --xml \'<state-change-slice>...</state-change-slice>\'');
1638
+ console.error('Run "eventmodeler create state-change-slice --help" for detailed format.');
567
1639
  process.exit(1);
568
1640
  }
569
1641
  createStateChangeSlice(model, filePath, xmlArg);
570
1642
  break;
571
1643
  }
572
1644
  case 'automation-slice': {
1645
+ if (helpRequested) {
1646
+ console.log(`
1647
+ eventmodeler create automation-slice - Create an automation slice
1648
+
1649
+ An automation slice represents system automation: ReadModel → Processor → Command → Event
1650
+
1651
+ USAGE:
1652
+ eventmodeler create automation-slice --xml <data>
1653
+
1654
+ XML FORMAT:
1655
+ <automation-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
1656
+ <read-model name="ReadModelName">
1657
+ <field name="fieldName" type="Type" [flags]/>
1658
+ </read-model>
1659
+ <processor name="ProcessorName">
1660
+ <field name="fieldName" type="Type" [flags]/>
1661
+ </processor>
1662
+ <command name="CommandName">
1663
+ <field name="fieldName" type="Type" [flags]/>
1664
+ </command>
1665
+ <event name="EventName">
1666
+ <field name="fieldName" type="Type" [flags]/>
1667
+ </event>
1668
+ </automation-slice>
1669
+
1670
+ POSITIONING (IMPORTANT):
1671
+ after="Slice Name" Place this slice immediately after the named slice
1672
+ before="Slice Name" Place this slice immediately before the named slice
1673
+ (shifts existing slices to the right)
1674
+
1675
+ If neither is specified, the slice is placed at the rightmost position.
1676
+ Use "eventmodeler list slices" to see existing slice names for positioning.
1677
+
1678
+ FIELD TYPES:
1679
+ UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
1680
+
1681
+ FIELD FLAGS (work on ALL fields and nested subfields):
1682
+ isList="true" Array/list of values
1683
+ isOptional="true" Nullable field
1684
+ isGenerated="true" Computed field (excluded from mapping completeness)
1685
+
1686
+ EXAMPLES:
1687
+ # Create automation slice after "Place Order" slice
1688
+ eventmodeler create automation-slice --xml '
1689
+ <automation-slice name="Auto-ship Order" after="Place Order">
1690
+ <read-model name="OrderReadyForShipment">
1691
+ <field name="orderId" type="UUID"/>
1692
+ <field name="shippingAddress" type="String"/>
1693
+ </read-model>
1694
+ <processor name="ShipmentScheduler">
1695
+ <field name="orderId" type="UUID"/>
1696
+ </processor>
1697
+ <command name="ScheduleShipment">
1698
+ <field name="orderId" type="UUID"/>
1699
+ </command>
1700
+ <event name="ShipmentScheduled">
1701
+ <field name="shipmentId" type="UUID" isGenerated="true"/>
1702
+ <field name="orderId" type="UUID"/>
1703
+ <field name="scheduledAt" type="DateTime" isGenerated="true"/>
1704
+ </event>
1705
+ </automation-slice>'
1706
+
1707
+ # Create automation slice before another slice
1708
+ eventmodeler create automation-slice --xml '
1709
+ <automation-slice name="Validate Inventory" before="Auto-ship Order">
1710
+ ...
1711
+ </automation-slice>'
1712
+ `);
1713
+ process.exit(0);
1714
+ }
573
1715
  const xmlArg = getNamedArg(filteredArgs, '--xml');
574
1716
  if (!xmlArg) {
575
1717
  console.error('Error: --xml is required');
576
1718
  console.error('Usage: eventmodeler create automation-slice --xml \'<automation-slice>...</automation-slice>\'');
1719
+ console.error('Run "eventmodeler create automation-slice --help" for detailed format.');
577
1720
  process.exit(1);
578
1721
  }
579
1722
  createAutomationSlice(model, filePath, xmlArg);
580
1723
  break;
581
1724
  }
582
1725
  case 'state-view-slice': {
1726
+ if (helpRequested) {
1727
+ console.log(`
1728
+ eventmodeler create state-view-slice - Create a state-view slice
1729
+
1730
+ A state-view slice represents a read model for displaying data.
1731
+
1732
+ USAGE:
1733
+ eventmodeler create state-view-slice --xml <data>
1734
+
1735
+ XML FORMAT:
1736
+ <state-view-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
1737
+ <read-model name="ReadModelName">
1738
+ <field name="fieldName" type="Type" [flags]/>
1739
+ </read-model>
1740
+ </state-view-slice>
1741
+
1742
+ POSITIONING (IMPORTANT):
1743
+ after="Slice Name" Place this slice immediately after the named slice
1744
+ before="Slice Name" Place this slice immediately before the named slice
1745
+ (shifts existing slices to the right)
1746
+
1747
+ If neither is specified, the slice is placed at the rightmost position.
1748
+ Use "eventmodeler list slices" to see existing slice names for positioning.
1749
+
1750
+ FIELD TYPES:
1751
+ UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
1752
+
1753
+ FIELD FLAGS (work on ALL fields and nested subfields):
1754
+ isList="true" Array/list of values
1755
+ isOptional="true" Nullable field
1756
+ isGenerated="true" Computed/aggregated field (common for dashboards)
1757
+
1758
+ EXAMPLES:
1759
+ # Create state-view slice after "Place Order" slice
1760
+ eventmodeler create state-view-slice --xml '
1761
+ <state-view-slice name="Order Dashboard" after="Place Order">
1762
+ <read-model name="OrderDashboard">
1763
+ <field name="totalOrders" type="Int" isGenerated="true"/>
1764
+ <field name="totalRevenue" type="Decimal" isGenerated="true"/>
1765
+ <field name="averageOrderValue" type="Decimal" isGenerated="true"/>
1766
+ <field name="recentOrders" type="Custom" isList="true">
1767
+ <field name="orderId" type="UUID"/>
1768
+ <field name="total" type="Decimal"/>
1769
+ <field name="status" type="String"/>
1770
+ </field>
1771
+ </read-model>
1772
+ </state-view-slice>'
1773
+
1774
+ # Create state-view slice before another slice
1775
+ eventmodeler create state-view-slice --xml '
1776
+ <state-view-slice name="Customer Summary" before="Order Dashboard">
1777
+ ...
1778
+ </state-view-slice>'
1779
+ `);
1780
+ process.exit(0);
1781
+ }
583
1782
  const xmlArg = getNamedArg(filteredArgs, '--xml');
584
1783
  if (!xmlArg) {
585
1784
  console.error('Error: --xml is required');
586
1785
  console.error('Usage: eventmodeler create state-view-slice --xml \'<state-view-slice>...</state-view-slice>\'');
1786
+ console.error('Run "eventmodeler create state-view-slice --help" for detailed format.');
587
1787
  process.exit(1);
588
1788
  }
589
1789
  createStateViewSlice(model, filePath, xmlArg);
590
1790
  break;
591
1791
  }
592
1792
  case 'flow': {
1793
+ if (helpRequested) {
1794
+ console.log(`
1795
+ eventmodeler create flow - Create a flow between elements
1796
+
1797
+ USAGE:
1798
+ eventmodeler create flow --from <source> --to <target>
1799
+
1800
+ OPTIONS:
1801
+ --from <name> Source element name (required)
1802
+ --to <name> Target element name (required)
1803
+
1804
+ VALID FLOW TYPES:
1805
+ Event → ReadModel Event data projects into read model
1806
+ ReadModel → Screen Read model provides data to UI
1807
+ ReadModel → Processor Read model triggers automation
1808
+
1809
+ EXAMPLES:
1810
+ eventmodeler create flow --from OrderPlaced --to OrderSummary
1811
+ eventmodeler create flow --from "Order Summary" --to "Order Dashboard Screen"
1812
+ eventmodeler create flow --from OrderReadyForShipment --to ShipmentProcessor
1813
+ `);
1814
+ process.exit(0);
1815
+ }
593
1816
  const fromArg = getNamedArg(filteredArgs, '--from');
594
1817
  const toArg = getNamedArg(filteredArgs, '--to');
595
1818
  if (!fromArg || !toArg) {
596
1819
  console.error('Error: --from and --to are required');
597
1820
  console.error('Usage: eventmodeler create flow --from <source> --to <target>');
598
- console.error('Valid flows: Event→ReadModel, ReadModel→Screen, ReadModel→Processor');
1821
+ console.error('Run "eventmodeler create flow --help" for more information.');
599
1822
  process.exit(1);
600
1823
  }
601
1824
  createFlow(model, filePath, fromArg, toArg);
@@ -604,16 +1827,61 @@ async function main() {
604
1827
  default:
605
1828
  console.error(`Unknown create target: ${subcommand}`);
606
1829
  console.error('Valid targets: state-change-slice, automation-slice, state-view-slice, flow');
1830
+ console.error('Run "eventmodeler create --help" for more information.');
607
1831
  process.exit(1);
608
1832
  }
609
1833
  break;
610
1834
  case 'codegen':
1835
+ if (helpRequested && !subcommand) {
1836
+ console.log(`
1837
+ eventmodeler codegen - Generate code-ready output
1838
+
1839
+ USAGE:
1840
+ eventmodeler codegen <type> [options]
1841
+
1842
+ TYPES:
1843
+ slice Generate comprehensive JSON for a slice
1844
+
1845
+ Run "eventmodeler codegen slice --help" for detailed help.
1846
+ `);
1847
+ process.exit(0);
1848
+ }
611
1849
  switch (subcommand) {
612
1850
  case 'slice': {
1851
+ if (helpRequested) {
1852
+ console.log(`
1853
+ eventmodeler codegen slice - Generate code-ready JSON for a slice
1854
+
1855
+ USAGE:
1856
+ eventmodeler codegen slice <name>
1857
+
1858
+ ARGUMENTS:
1859
+ <name> Slice name
1860
+
1861
+ OUTPUT:
1862
+ Comprehensive JSON including:
1863
+ - Slice metadata (name, type, chapter, aggregate)
1864
+ - All components with full field definitions
1865
+ - Fields include: name, type, isList, isOptional, isGenerated
1866
+ - Nested subfields for Custom types (all flags preserved)
1867
+ - Field mappings between components
1868
+ - Scenarios (Given-When-Then specifications)
1869
+ - Dependencies (inbound/outbound flows)
1870
+
1871
+ This output is designed for code generation tools and includes
1872
+ all information needed to generate implementation code.
1873
+
1874
+ EXAMPLES:
1875
+ eventmodeler codegen slice "Place Order"
1876
+ eventmodeler codegen slice PlaceOrder > slice.json
1877
+ `);
1878
+ process.exit(0);
1879
+ }
613
1880
  const sliceName = filteredArgs[2];
614
1881
  if (!sliceName) {
615
1882
  console.error('Error: slice name is required');
616
1883
  console.error('Usage: eventmodeler codegen slice <name>');
1884
+ console.error('Run "eventmodeler codegen slice --help" for more information.');
617
1885
  process.exit(1);
618
1886
  }
619
1887
  codegenSlice(model, sliceName);
@@ -622,6 +1890,7 @@ async function main() {
622
1890
  default:
623
1891
  console.error(`Unknown codegen target: ${subcommand}`);
624
1892
  console.error('Valid targets: slice');
1893
+ console.error('Run "eventmodeler codegen --help" for more information.');
625
1894
  process.exit(1);
626
1895
  }
627
1896
  break;