@diagrammo/dgmo 0.8.2 → 0.8.4

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.
Files changed (120) hide show
  1. package/.claude/commands/dgmo-diagram-this.md +60 -0
  2. package/.claude/commands/dgmo-document-project.md +128 -0
  3. package/.claude/commands/dgmo.md +185 -50
  4. package/.cursorrules +32 -37
  5. package/.github/copilot-instructions.md +35 -44
  6. package/.windsurfrules +32 -37
  7. package/README.md +4 -4
  8. package/dist/cli.cjs +189 -194
  9. package/dist/editor.cjs +336 -0
  10. package/dist/editor.cjs.map +1 -0
  11. package/dist/editor.d.cts +27 -0
  12. package/dist/editor.d.ts +27 -0
  13. package/dist/editor.js +305 -0
  14. package/dist/editor.js.map +1 -0
  15. package/dist/index.cjs +3699 -1564
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +7 -6
  18. package/dist/index.d.ts +7 -6
  19. package/dist/index.js +3699 -1564
  20. package/dist/index.js.map +1 -1
  21. package/docs/language-reference.md +822 -1060
  22. package/gallery/fixtures/arc.dgmo +18 -0
  23. package/gallery/fixtures/area.dgmo +19 -0
  24. package/gallery/fixtures/bar-stacked.dgmo +10 -0
  25. package/gallery/fixtures/bar.dgmo +10 -0
  26. package/gallery/fixtures/c4-full.dgmo +52 -0
  27. package/gallery/fixtures/c4.dgmo +17 -0
  28. package/gallery/fixtures/chord.dgmo +12 -0
  29. package/gallery/fixtures/class-basic.dgmo +14 -0
  30. package/gallery/fixtures/class-full.dgmo +43 -0
  31. package/gallery/fixtures/doughnut.dgmo +8 -0
  32. package/gallery/fixtures/flowchart-basic.dgmo +3 -0
  33. package/gallery/fixtures/flowchart-colors.dgmo +5 -0
  34. package/gallery/fixtures/flowchart-complex.dgmo +17 -0
  35. package/gallery/fixtures/flowchart-decision.dgmo +5 -0
  36. package/gallery/fixtures/flowchart-full.dgmo +13 -0
  37. package/gallery/fixtures/flowchart-groups.dgmo +10 -0
  38. package/gallery/fixtures/flowchart-loop.dgmo +7 -0
  39. package/gallery/fixtures/flowchart-nested.dgmo +7 -0
  40. package/gallery/fixtures/flowchart-shapes.dgmo +5 -0
  41. package/gallery/fixtures/function.dgmo +8 -0
  42. package/gallery/fixtures/funnel.dgmo +7 -0
  43. package/gallery/fixtures/gantt-full.dgmo +49 -0
  44. package/gallery/fixtures/gantt.dgmo +42 -0
  45. package/gallery/fixtures/heatmap.dgmo +8 -0
  46. package/gallery/fixtures/infra-full.dgmo +78 -0
  47. package/gallery/fixtures/infra-overload.dgmo +25 -0
  48. package/gallery/fixtures/infra.dgmo +47 -0
  49. package/gallery/fixtures/initiative-status-full.dgmo +46 -0
  50. package/gallery/fixtures/initiative-status-phases.dgmo +29 -0
  51. package/gallery/fixtures/initiative-status.dgmo +9 -0
  52. package/gallery/fixtures/line.dgmo +19 -0
  53. package/gallery/fixtures/multi-line.dgmo +11 -0
  54. package/gallery/fixtures/org-basic.dgmo +16 -0
  55. package/gallery/fixtures/org-full.dgmo +69 -0
  56. package/gallery/fixtures/org-teams.dgmo +25 -0
  57. package/gallery/fixtures/pie.dgmo +9 -0
  58. package/gallery/fixtures/polar-area.dgmo +8 -0
  59. package/gallery/fixtures/quadrant.dgmo +18 -0
  60. package/gallery/fixtures/radar.dgmo +8 -0
  61. package/gallery/fixtures/sankey.dgmo +31 -0
  62. package/gallery/fixtures/scatter.dgmo +21 -0
  63. package/gallery/fixtures/sequence-tags-protocols.dgmo +45 -0
  64. package/gallery/fixtures/sequence-tags.dgmo +41 -0
  65. package/gallery/fixtures/sequence.dgmo +35 -0
  66. package/gallery/fixtures/sitemap-basic.dgmo +12 -0
  67. package/gallery/fixtures/sitemap-full.dgmo +156 -0
  68. package/gallery/fixtures/slope.dgmo +8 -0
  69. package/gallery/fixtures/spr-eras.dgmo +62 -0
  70. package/gallery/fixtures/state.dgmo +30 -0
  71. package/gallery/fixtures/timeline-intraday.dgmo +14 -0
  72. package/gallery/fixtures/timeline.dgmo +32 -0
  73. package/gallery/fixtures/venn.dgmo +10 -0
  74. package/gallery/fixtures/wordcloud.dgmo +24 -0
  75. package/package.json +51 -2
  76. package/src/c4/layout.ts +372 -90
  77. package/src/c4/parser.ts +113 -62
  78. package/src/chart.ts +149 -64
  79. package/src/class/parser.ts +84 -28
  80. package/src/class/renderer.ts +2 -2
  81. package/src/cli.ts +179 -77
  82. package/src/completion.ts +381 -182
  83. package/src/d3.ts +1026 -428
  84. package/src/dgmo-mermaid.ts +16 -13
  85. package/src/dgmo-router.ts +70 -24
  86. package/src/echarts.ts +682 -169
  87. package/src/editor/dgmo.grammar +69 -0
  88. package/src/editor/dgmo.grammar.d.ts +2 -0
  89. package/src/editor/dgmo.grammar.js +18 -0
  90. package/src/editor/dgmo.grammar.terms.d.ts +5 -0
  91. package/src/editor/dgmo.grammar.terms.js +35 -0
  92. package/src/editor/highlight.ts +36 -0
  93. package/src/editor/index.ts +28 -0
  94. package/src/editor/keywords.ts +220 -0
  95. package/src/editor/tokens.ts +30 -0
  96. package/src/er/parser.ts +55 -29
  97. package/src/er/renderer.ts +112 -53
  98. package/src/gantt/calculator.ts +91 -29
  99. package/src/gantt/parser.ts +291 -97
  100. package/src/gantt/renderer.ts +1120 -350
  101. package/src/graph/flowchart-parser.ts +48 -75
  102. package/src/graph/state-parser.ts +54 -27
  103. package/src/infra/parser.ts +161 -177
  104. package/src/infra/renderer.ts +723 -271
  105. package/src/infra/types.ts +0 -1
  106. package/src/initiative-status/parser.ts +144 -56
  107. package/src/kanban/parser.ts +27 -19
  108. package/src/org/layout.ts +111 -44
  109. package/src/org/parser.ts +71 -27
  110. package/src/org/resolver.ts +3 -3
  111. package/src/palettes/index.ts +3 -2
  112. package/src/render.ts +1 -2
  113. package/src/sequence/parser.ts +209 -100
  114. package/src/sitemap/parser.ts +73 -44
  115. package/src/utils/arrows.ts +2 -22
  116. package/src/utils/duration.ts +39 -21
  117. package/src/utils/legend-constants.ts +0 -2
  118. package/src/utils/parsing.ts +82 -72
  119. package/src/utils/tag-groups.ts +4 -41
  120. package/src/infra/serialize.ts +0 -67
package/src/cli.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
3
  import { execSync } from 'node:child_process';
3
4
  import { homedir } from 'node:os';
@@ -47,7 +48,8 @@ const CHART_TYPE_DESCRIPTIONS: Record<string, string> = {
47
48
  org: 'Org chart — hierarchical tree structures',
48
49
  kanban: 'Kanban board — task/workflow columns',
49
50
  c4: 'C4 diagram — system architecture (context, container, component, deployment)',
50
- 'initiative-status': 'Initiative status — project roadmap with dependency tracking',
51
+ 'initiative-status':
52
+ 'Initiative status — project roadmap with dependency tracking',
51
53
  infra: 'Infra chart — infrastructure traffic flow with rps computation',
52
54
  };
53
55
 
@@ -199,7 +201,7 @@ Key options:
199
201
  ### Common to all diagrams
200
202
 
201
203
  \`\`\`
202
- chart: sequence // explicit type (optional — auto-detected)
204
+ sequence // explicit type (optional — auto-detected)
203
205
  title: My Diagram
204
206
  palette: catppuccin // override palette
205
207
 
@@ -372,8 +374,7 @@ When the \`dgmo\` MCP server is configured, use these tools directly:
372
374
 
373
375
  ### Sequence diagram
374
376
  \`\`\`
375
- chart: sequence
376
- title: Auth Flow
377
+ sequence Auth Flow
377
378
 
378
379
  User -Login-> API
379
380
  API -Find user-> DB
@@ -386,8 +387,7 @@ DB -user-> API
386
387
 
387
388
  ### Flowchart
388
389
  \`\`\`
389
- chart: flowchart
390
- title: Process
390
+ flowchart Process
391
391
 
392
392
  (Start) -> <Valid?>
393
393
  -yes-> [Process] -> (Done)
@@ -396,8 +396,7 @@ title: Process
396
396
 
397
397
  ### Bar chart
398
398
  \`\`\`
399
- chart: bar
400
- title: Revenue
399
+ bar Revenue
401
400
  series: USD
402
401
 
403
402
  North: 850
@@ -407,8 +406,7 @@ East: 1100
407
406
 
408
407
  ### ER diagram
409
408
  \`\`\`
410
- chart: er
411
- title: Schema
409
+ er Schema
412
410
 
413
411
  users
414
412
  id: int [pk]
@@ -423,7 +421,7 @@ users 1--* posts : writes
423
421
 
424
422
  ### Org chart
425
423
  \`\`\`
426
- chart: org
424
+ org
427
425
 
428
426
  CEO
429
427
  VP Engineering
@@ -434,8 +432,7 @@ CEO
434
432
 
435
433
  ### Infra chart
436
434
  \`\`\`
437
- chart: infra
438
- direction: LR
435
+ infra
439
436
 
440
437
  edge
441
438
  rps: 10000
@@ -461,7 +458,7 @@ bar, line, multi-line, area, pie, doughnut, radar, polar-area, bar-stacked, scat
461
458
 
462
459
  ## Common patterns
463
460
 
464
- - \`chart: type\` explicit chart type (auto-detected if unambiguous)
461
+ - First line: chart type keyword (e.g. \`sequence\`, \`flowchart\`, \`bar\`) auto-detected if unambiguous
465
462
  - \`title: text\` — diagram title
466
463
  - \`// comment\` — only \`//\` comments (not \`#\`)
467
464
  - \`(colorname)\` — inline colors: \`Label(red): 100\`
@@ -480,7 +477,7 @@ dgmo file.dgmo --json # structured JSON output
480
477
  - Don't use \`#\` for comments — use \`//\`
481
478
  - Don't use \`end\` to close sequence blocks — indentation closes them
482
479
  - Don't use hex colors in section headers — use named colors
483
- - Don't forget \`chart:\` directive when content is ambiguous
480
+ - Start the file with the chart type keyword when content is ambiguous
484
481
  - Sequence arrows: \`->\` (sync), \`~>\` (async) — always left-to-right
485
482
 
486
483
  Full reference: call \`get_language_reference\` MCP tool or visit diagrammo.app/docs
@@ -559,7 +556,11 @@ function parseArgs(argv: string[]): {
559
556
  installClaudeSkill: false,
560
557
  installClaudeCodeIntegration: false,
561
558
  installCodexIntegration: false,
562
- c4Level: 'context' as 'context' | 'containers' | 'components' | 'deployment',
559
+ c4Level: 'context' as
560
+ | 'context'
561
+ | 'containers'
562
+ | 'components'
563
+ | 'deployment',
563
564
  c4System: undefined as string | undefined,
564
565
  c4Container: undefined as string | undefined,
565
566
  tagGroup: undefined as string | undefined,
@@ -602,7 +603,12 @@ function parseArgs(argv: string[]): {
602
603
  i++;
603
604
  } else if (arg === '--c4-level') {
604
605
  const val = args[++i];
605
- if (val !== 'context' && val !== 'containers' && val !== 'components' && val !== 'deployment') {
606
+ if (
607
+ val !== 'context' &&
608
+ val !== 'containers' &&
609
+ val !== 'components' &&
610
+ val !== 'deployment'
611
+ ) {
606
612
  console.error(
607
613
  `Error: Invalid C4 level "${val}". Valid levels: context, containers, components, deployment`
608
614
  );
@@ -686,8 +692,8 @@ function noInput(): never {
686
692
  writeFileSync(
687
693
  samplePath,
688
694
  [
689
- 'chart: sequence',
690
- 'activations: off',
695
+ 'sequence',
696
+ 'activations off',
691
697
  '',
692
698
  'Client -POST /login-> API',
693
699
  ' API -validate credentials-> Auth',
@@ -750,8 +756,14 @@ async function main(): Promise<void> {
750
756
 
751
757
  function ask(prompt: string): Promise<string> {
752
758
  return new Promise((resolve) => {
753
- const rl = createInterface({ input: process.stdin, output: process.stdout });
754
- rl.question(prompt, (answer) => { rl.close(); resolve(answer); });
759
+ const rl = createInterface({
760
+ input: process.stdin,
761
+ output: process.stdout,
762
+ });
763
+ rl.question(prompt, (answer) => {
764
+ rl.close();
765
+ resolve(answer);
766
+ });
755
767
  });
756
768
  }
757
769
 
@@ -761,7 +773,9 @@ async function main(): Promise<void> {
761
773
  const skillExists = existsSync(skillPath);
762
774
  let installSkill = true;
763
775
  if (skillExists) {
764
- const ans = await ask('~/.claude/commands/dgmo.md already exists. Overwrite? [y/N] ');
776
+ const ans = await ask(
777
+ '~/.claude/commands/dgmo.md already exists. Overwrite? [y/N] '
778
+ );
765
779
  installSkill = ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
766
780
  }
767
781
  if (installSkill) {
@@ -774,16 +788,26 @@ async function main(): Promise<void> {
774
788
 
775
789
  // --- Step 2: Check / install dgmo-mcp binary ---
776
790
  let dgmoMcpInstalled = false;
777
- try { execSync('which dgmo-mcp', { stdio: 'pipe' }); dgmoMcpInstalled = true; } catch { /* not found */ }
791
+ try {
792
+ execSync('which dgmo-mcp', { stdio: 'pipe' });
793
+ dgmoMcpInstalled = true;
794
+ } catch {
795
+ /* not found */
796
+ }
778
797
  if (!dgmoMcpInstalled) {
779
- const ans = await ask('\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] ');
780
- const yes = ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
798
+ const ans = await ask(
799
+ '\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] '
800
+ );
801
+ const yes =
802
+ ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
781
803
  if (yes) {
782
804
  console.log('Installing @diagrammo/dgmo-mcp...');
783
805
  execSync('npm install -g @diagrammo/dgmo-mcp', { stdio: 'inherit' });
784
806
  console.log('✓ @diagrammo/dgmo-mcp installed');
785
807
  } else {
786
- console.log(' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp');
808
+ console.log(
809
+ ' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp'
810
+ );
787
811
  }
788
812
  } else {
789
813
  console.log('✓ dgmo-mcp already installed');
@@ -792,7 +816,9 @@ async function main(): Promise<void> {
792
816
  // --- Step 3: Configure MCP server ---
793
817
  console.log('\nWhere should the MCP server be configured?');
794
818
  console.log(' 1) This project only — write .mcp.json here [default]');
795
- console.log(' 2) Globally — add to ~/.claude/settings.json (works in all projects)');
819
+ console.log(
820
+ ' 2) Globally — add to ~/.claude/settings.json (works in all projects)'
821
+ );
796
822
  const scopeAns = await ask('\nChoice [1]: ');
797
823
  const useGlobal = scopeAns.trim() === '2';
798
824
  const mcpEntry = { command: 'dgmo-mcp' };
@@ -801,24 +827,40 @@ async function main(): Promise<void> {
801
827
  const settingsPath = join(claudeDir, 'settings.json');
802
828
  let settings: Record<string, unknown> = {};
803
829
  if (existsSync(settingsPath)) {
804
- try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* use empty */ }
830
+ try {
831
+ settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
832
+ } catch {
833
+ /* use empty */
834
+ }
805
835
  }
806
- const mcpServers = (settings.mcpServers as Record<string, unknown> | undefined) ?? {};
836
+ const mcpServers =
837
+ (settings.mcpServers as Record<string, unknown> | undefined) ?? {};
807
838
  mcpServers['dgmo'] = mcpEntry;
808
839
  settings.mcpServers = mcpServers;
809
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
840
+ writeFileSync(
841
+ settingsPath,
842
+ JSON.stringify(settings, null, 2) + '\n',
843
+ 'utf-8'
844
+ );
810
845
  console.log('✓ MCP server added to ~/.claude/settings.json');
811
846
  } else {
812
847
  const mcpPath = join(process.cwd(), '.mcp.json');
813
848
  let mcp: Record<string, unknown> = {};
814
849
  if (existsSync(mcpPath)) {
815
- try { mcp = JSON.parse(readFileSync(mcpPath, 'utf-8')); } catch { /* use empty */ }
850
+ try {
851
+ mcp = JSON.parse(readFileSync(mcpPath, 'utf-8'));
852
+ } catch {
853
+ /* use empty */
854
+ }
816
855
  }
817
- const mcpServers = (mcp.mcpServers as Record<string, unknown> | undefined) ?? {};
856
+ const mcpServers =
857
+ (mcp.mcpServers as Record<string, unknown> | undefined) ?? {};
818
858
  mcpServers['dgmo'] = mcpEntry;
819
859
  mcp.mcpServers = mcpServers;
820
860
  writeFileSync(mcpPath, JSON.stringify(mcp, null, 2) + '\n', 'utf-8');
821
- console.log(`✓ MCP server configured: ${join(process.cwd(), '.mcp.json')}`);
861
+ console.log(
862
+ `✓ MCP server configured: ${join(process.cwd(), '.mcp.json')}`
863
+ );
822
864
  }
823
865
 
824
866
  console.log('\nRestart Claude Code to activate the MCP server.');
@@ -840,12 +882,17 @@ async function main(): Promise<void> {
840
882
  ? `~/.claude/commands/dgmo.md already exists. Overwrite? [y/N] `
841
883
  : `Install dgmo Claude Code skill to ~/.claude/commands/dgmo.md? [Y/n] `;
842
884
  await new Promise<void>((done) => {
843
- const rl = createInterface({ input: process.stdin, output: process.stdout });
885
+ const rl = createInterface({
886
+ input: process.stdin,
887
+ output: process.stdout,
888
+ });
844
889
  rl.question(prompt, (answer) => {
845
890
  rl.close();
846
891
  const yes = alreadyExists
847
892
  ? answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes'
848
- : answer === '' || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
893
+ : answer === '' ||
894
+ answer.toLowerCase() === 'y' ||
895
+ answer.toLowerCase() === 'yes';
849
896
  if (!yes) {
850
897
  console.error('Aborted.');
851
898
  process.exit(0);
@@ -864,23 +911,41 @@ async function main(): Promise<void> {
864
911
 
865
912
  if (opts.installCodexIntegration) {
866
913
  // Validate Codex CLI is installed
867
- try { execSync('which codex', { stdio: 'pipe' }); } catch {
868
- console.error('codex not found. Install Codex CLI first: https://openai.com/codex');
914
+ try {
915
+ execSync('which codex', { stdio: 'pipe' });
916
+ } catch {
917
+ console.error(
918
+ 'codex not found. Install Codex CLI first: https://openai.com/codex'
919
+ );
869
920
  process.exit(1);
870
921
  }
871
922
 
872
923
  const ask = (prompt: string): Promise<string> =>
873
924
  new Promise((resolve) => {
874
- const rl = createInterface({ input: process.stdin, output: process.stdout });
875
- rl.question(prompt, (answer) => { rl.close(); resolve(answer); });
925
+ const rl = createInterface({
926
+ input: process.stdin,
927
+ output: process.stdout,
928
+ });
929
+ rl.question(prompt, (answer) => {
930
+ rl.close();
931
+ resolve(answer);
932
+ });
876
933
  });
877
934
 
878
935
  // Check / install dgmo-mcp binary
879
936
  let dgmoMcpInstalled = false;
880
- try { execSync('which dgmo-mcp', { stdio: 'pipe' }); dgmoMcpInstalled = true; } catch { /* not found */ }
937
+ try {
938
+ execSync('which dgmo-mcp', { stdio: 'pipe' });
939
+ dgmoMcpInstalled = true;
940
+ } catch {
941
+ /* not found */
942
+ }
881
943
  if (!dgmoMcpInstalled) {
882
- const ans = await ask('\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] ');
883
- const yes = ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
944
+ const ans = await ask(
945
+ '\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] '
946
+ );
947
+ const yes =
948
+ ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
884
949
  if (yes) {
885
950
  console.log('Installing @diagrammo/dgmo-mcp...');
886
951
  try {
@@ -891,7 +956,9 @@ async function main(): Promise<void> {
891
956
  console.error('Try manually: npm install -g @diagrammo/dgmo-mcp');
892
957
  }
893
958
  } else {
894
- console.log(' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp');
959
+ console.log(
960
+ ' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp'
961
+ );
895
962
  }
896
963
  } else {
897
964
  console.log('✓ dgmo-mcp already installed');
@@ -899,11 +966,21 @@ async function main(): Promise<void> {
899
966
 
900
967
  // Configure MCP server
901
968
  console.log('\nWhere should the MCP server be configured?');
902
- console.log(' 1) This project only — write .codex/config.toml here [default]');
903
- console.log(' 2) Globallyadd to ~/.codex/config.toml (works in all projects)');
969
+ console.log(
970
+ ' 1) This project only write .codex/config.toml here [default]'
971
+ );
972
+ console.log(
973
+ ' 2) Globally — add to ~/.codex/config.toml (works in all projects)'
974
+ );
904
975
  const scopeAns = await ask('\nChoice [1]: ');
905
- if (scopeAns.trim() !== '' && scopeAns.trim() !== '1' && scopeAns.trim() !== '2') {
906
- console.log(` Unrecognized input "${scopeAns.trim()}", defaulting to option 1.`);
976
+ if (
977
+ scopeAns.trim() !== '' &&
978
+ scopeAns.trim() !== '1' &&
979
+ scopeAns.trim() !== '2'
980
+ ) {
981
+ console.log(
982
+ ` Unrecognized input "${scopeAns.trim()}", defaulting to option 1.`
983
+ );
907
984
  }
908
985
  const useGlobal = scopeAns.trim() === '2';
909
986
  const tomlEntry = '[mcp_servers.dgmo]\ncommand = ["dgmo-mcp"]\n';
@@ -911,7 +988,9 @@ async function main(): Promise<void> {
911
988
  if (useGlobal) {
912
989
  const configPath = join(homedir(), '.codex', 'config.toml');
913
990
  mkdirSync(join(homedir(), '.codex'), { recursive: true });
914
- const existing = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
991
+ const existing = existsSync(configPath)
992
+ ? readFileSync(configPath, 'utf-8')
993
+ : '';
915
994
  if (existing.includes('[mcp_servers.dgmo]')) {
916
995
  console.log('✓ MCP server already configured in ~/.codex/config.toml');
917
996
  } else {
@@ -923,7 +1002,9 @@ async function main(): Promise<void> {
923
1002
  const codexDir = join(process.cwd(), '.codex');
924
1003
  const configPath = join(codexDir, 'config.toml');
925
1004
  mkdirSync(codexDir, { recursive: true });
926
- const existing = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
1005
+ const existing = existsSync(configPath)
1006
+ ? readFileSync(configPath, 'utf-8')
1007
+ : '';
927
1008
  if (existing.includes('[mcp_servers.dgmo]')) {
928
1009
  console.log(`✓ MCP server already configured in .codex/config.toml`);
929
1010
  } else {
@@ -988,10 +1069,8 @@ async function main(): Promise<void> {
988
1069
  // Resolve org chart imports (tags and import directives)
989
1070
  if (opts.input && parseDgmoChartType(content) === 'org') {
990
1071
  const inputPath = resolve(opts.input);
991
- const resolved = await resolveOrgImports(
992
- content,
993
- inputPath,
994
- (p) => readFileSync(p, 'utf-8'),
1072
+ const resolved = await resolveOrgImports(content, inputPath, (p) =>
1073
+ readFileSync(p, 'utf-8')
995
1074
  );
996
1075
  for (const diag of resolved.diagnostics) {
997
1076
  console.error(formatDgmoError(diag));
@@ -1013,12 +1092,18 @@ async function main(): Promise<void> {
1013
1092
  // Helper for JSON error output
1014
1093
  function exitWithJsonError(error: string, line?: number): never {
1015
1094
  if (opts.json) {
1016
- process.stdout.write(JSON.stringify({
1017
- success: false,
1018
- error,
1019
- ...(line != null ? { line } : {}),
1020
- ...(chartType ? { chartType } : {}),
1021
- }, null, 2) + '\n');
1095
+ process.stdout.write(
1096
+ JSON.stringify(
1097
+ {
1098
+ success: false,
1099
+ error,
1100
+ ...(line != null ? { line } : {}),
1101
+ ...(chartType ? { chartType } : {}),
1102
+ },
1103
+ null,
1104
+ 2
1105
+ ) + '\n'
1106
+ );
1022
1107
  } else {
1023
1108
  console.error(error);
1024
1109
  }
@@ -1051,18 +1136,26 @@ async function main(): Promise<void> {
1051
1136
  }
1052
1137
 
1053
1138
  if (opts.json) {
1054
- process.stdout.write(JSON.stringify({
1055
- success: true,
1056
- url: result.url,
1057
- ...(chartType ? { chartType } : {}),
1058
- }, null, 2) + '\n');
1139
+ process.stdout.write(
1140
+ JSON.stringify(
1141
+ {
1142
+ success: true,
1143
+ url: result.url,
1144
+ ...(chartType ? { chartType } : {}),
1145
+ },
1146
+ null,
1147
+ 2
1148
+ ) + '\n'
1149
+ );
1059
1150
  } else {
1060
1151
  process.stdout.write(result.url + '\n');
1061
1152
  }
1062
1153
  return;
1063
1154
  }
1064
1155
 
1065
- const paletteColors = getPalette(opts.palette)[opts.theme === 'dark' ? 'dark' : 'light'];
1156
+ const paletteColors = getPalette(opts.palette)[
1157
+ opts.theme === 'dark' ? 'dark' : 'light'
1158
+ ];
1066
1159
 
1067
1160
  // Word clouds require Canvas APIs (HTMLCanvasElement.getContext('2d'))
1068
1161
  // which are unavailable in Node.js — check before attempting render.
@@ -1089,10 +1182,7 @@ async function main(): Promise<void> {
1089
1182
  if (errors.length > 0) {
1090
1183
  if (opts.json) {
1091
1184
  const firstError = errors[0];
1092
- exitWithJsonError(
1093
- formatDgmoError(firstError),
1094
- firstError.line,
1095
- );
1185
+ exitWithJsonError(formatDgmoError(firstError), firstError.line);
1096
1186
  }
1097
1187
  for (const e of errors) {
1098
1188
  console.error(`\u2716 ${formatDgmoError(e)}`);
@@ -1101,14 +1191,20 @@ async function main(): Promise<void> {
1101
1191
 
1102
1192
  // Validate C4 options
1103
1193
  if (opts.c4Level === 'containers' && !opts.c4System) {
1104
- exitWithJsonError('Error: --c4-system is required when --c4-level is containers');
1194
+ exitWithJsonError(
1195
+ 'Error: --c4-system is required when --c4-level is containers'
1196
+ );
1105
1197
  }
1106
1198
  if (opts.c4Level === 'components') {
1107
1199
  if (!opts.c4System) {
1108
- exitWithJsonError('Error: --c4-system is required when --c4-level is components');
1200
+ exitWithJsonError(
1201
+ 'Error: --c4-system is required when --c4-level is components'
1202
+ );
1109
1203
  }
1110
1204
  if (!opts.c4Container) {
1111
- exitWithJsonError('Error: --c4-container is required when --c4-level is components');
1205
+ exitWithJsonError(
1206
+ 'Error: --c4-container is required when --c4-level is components'
1207
+ );
1112
1208
  }
1113
1209
  }
1114
1210
 
@@ -1148,11 +1244,17 @@ async function main(): Promise<void> {
1148
1244
  outputPath = resolve(`${inputBasename}.png`);
1149
1245
  writeFileSync(outputPath, svgToPng(svg, pngBg));
1150
1246
  }
1151
- process.stdout.write(JSON.stringify({
1152
- success: true,
1153
- ...(outputPath ? { output: outputPath } : {}),
1154
- ...(chartType ? { chartType } : {}),
1155
- }, null, 2) + '\n');
1247
+ process.stdout.write(
1248
+ JSON.stringify(
1249
+ {
1250
+ success: true,
1251
+ ...(outputPath ? { output: outputPath } : {}),
1252
+ ...(chartType ? { chartType } : {}),
1253
+ },
1254
+ null,
1255
+ 2
1256
+ ) + '\n'
1257
+ );
1156
1258
  } else if (opts.output) {
1157
1259
  // Explicit output path
1158
1260
  const outputPath = resolve(opts.output);