@diagrammo/dgmo 0.6.2 → 0.6.3

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 (44) hide show
  1. package/.claude/commands/dgmo.md +231 -13
  2. package/AGENTS.md +148 -0
  3. package/dist/cli.cjs +327 -153
  4. package/dist/index.cjs +305 -177
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +24 -3
  7. package/dist/index.d.ts +24 -3
  8. package/dist/index.js +303 -177
  9. package/dist/index.js.map +1 -1
  10. package/package.json +5 -3
  11. package/src/c4/layout.ts +0 -5
  12. package/src/c4/parser.ts +0 -16
  13. package/src/c4/renderer.ts +1 -5
  14. package/src/class/layout.ts +0 -1
  15. package/src/class/parser.ts +28 -0
  16. package/src/class/renderer.ts +5 -26
  17. package/src/cli.ts +563 -14
  18. package/src/completion.ts +58 -0
  19. package/src/d3.ts +58 -106
  20. package/src/dgmo-router.ts +0 -57
  21. package/src/echarts.ts +96 -55
  22. package/src/er/parser.ts +30 -1
  23. package/src/er/renderer.ts +1 -2
  24. package/src/graph/flowchart-parser.ts +27 -4
  25. package/src/graph/flowchart-renderer.ts +1 -2
  26. package/src/graph/state-parser.ts +0 -1
  27. package/src/graph/state-renderer.ts +1 -3
  28. package/src/index.ts +10 -0
  29. package/src/infra/compute.ts +0 -7
  30. package/src/infra/layout.ts +0 -2
  31. package/src/infra/parser.ts +46 -4
  32. package/src/infra/renderer.ts +1 -15
  33. package/src/initiative-status/renderer.ts +5 -25
  34. package/src/kanban/parser.ts +0 -2
  35. package/src/org/layout.ts +0 -4
  36. package/src/org/renderer.ts +7 -28
  37. package/src/sequence/parser.ts +14 -11
  38. package/src/sequence/renderer.ts +0 -2
  39. package/src/sequence/tag-resolution.ts +0 -1
  40. package/src/sitemap/layout.ts +1 -14
  41. package/src/sitemap/parser.ts +1 -2
  42. package/src/sitemap/renderer.ts +0 -3
  43. package/src/utils/arrows.ts +7 -7
  44. package/src/utils/export-container.ts +40 -0
package/src/cli.ts CHANGED
@@ -65,7 +65,93 @@ You are helping the user author, render, and share diagrams using the \`dgmo\` C
65
65
 
66
66
  ## What is dgmo?
67
67
 
68
- \`dgmo\` is a CLI tool that renders \`.dgmo\` diagram files to PNG, SVG, or shareable URLs. Diagrams are written in a plain-text DSL.
68
+ \`dgmo\` is a CLI tool and library that renders \`.dgmo\` diagram files to PNG, SVG, or shareable URLs. Diagrams are written in a plain-text DSL.
69
+
70
+ ## Setup Check — Run This First
71
+
72
+ **Before doing anything else**, check whether the MCP tools are available in this session by attempting to call \`mcp__dgmo__list_chart_types\`. If that tool exists and succeeds, skip this section entirely.
73
+
74
+ If the MCP tools are **not** available, run the setup flow below — do not ask the user, just do it:
75
+
76
+ ### Step 1 — Install the CLI (if missing)
77
+
78
+ \`\`\`bash
79
+ which dgmo || npm install -g @diagrammo/dgmo
80
+ \`\`\`
81
+
82
+ ### Step 2 — Install the MCP server (if missing)
83
+
84
+ \`\`\`bash
85
+ which dgmo-mcp || npm install -g @diagrammo/dgmo-mcp
86
+ \`\`\`
87
+
88
+ ### Step 3 — Configure the MCP server
89
+
90
+ Ask the user:
91
+
92
+ > "Where should I configure the MCP server?
93
+ > 1) This project only — write \`.mcp.json\` here [default]
94
+ > 2) Globally — add to \`~/.claude/settings.json\` (works in all projects)"
95
+
96
+ **Option 1 (default):** Create or update \`.mcp.json\` in the current working directory:
97
+
98
+ \`\`\`json
99
+ {
100
+ "mcpServers": {
101
+ "dgmo": {
102
+ "command": "dgmo-mcp"
103
+ }
104
+ }
105
+ }
106
+ \`\`\`
107
+
108
+ If \`.mcp.json\` already exists and has other servers, merge the \`dgmo\` entry in — do not overwrite the file.
109
+
110
+ **Option 2 (global):** Add the \`dgmo\` entry to the \`mcpServers\` object in \`~/.claude/settings.json\`. Read the file first and merge — do not overwrite other keys.
111
+
112
+ ### Step 4 — Prompt restart
113
+
114
+ Tell the user:
115
+
116
+ > "Done. **Restart Claude Code** to activate the MCP server — diagram preview and rendering will be available in the next session."
117
+
118
+ Then proceed with the user's original request using CLI fallback (see "Other output options" below).
119
+
120
+ > **Note for future users:** To set up in one step from the terminal before starting a Claude Code session, run \`dgmo --install-claude-code-integration\`. It handles everything: installs \`@diagrammo/dgmo-mcp\`, writes the skill, and configures the MCP server.
121
+
122
+ ## Getting Syntax Help
123
+
124
+ **Always use the MCP tool first** if it's available in this session:
125
+
126
+ \`\`\`
127
+ mcp__dgmo__get_language_reference // full reference
128
+ mcp__dgmo__get_language_reference("sequence") // specific chart type
129
+ \`\`\`
130
+
131
+ This is the authoritative, always-up-to-date syntax reference. Use it before guessing syntax.
132
+
133
+ ## Your Workflow
134
+
135
+ When the user asks you to create or edit a diagram:
136
+
137
+ 1. **Get syntax** — call \`mcp__dgmo__get_language_reference("<type>")\` if you're unsure of the syntax.
138
+ 2. **Write the \`.dgmo\` content** — compose the markup.
139
+ 3. **Save the source file** (if working in a project) — write it to \`<name>.dgmo\` so the user has an editable file.
140
+ 4. **Render and show** — pick the right output based on what the user wants (see below).
141
+
142
+ ### Output options — always offer these proactively after creating a diagram
143
+
144
+ | What the user wants | How to do it |
145
+ |---|---|
146
+ | **Quick look in the desktop app** | \`mcp__dgmo__open_in_app(dgmo)\` — opens directly in Diagrammo (macOS) |
147
+ | **Browser preview with theme toggle** | \`mcp__dgmo__preview_diagram([{dgmo, title}])\` — opens HTML in browser |
148
+ | **View in macOS Preview (or default image viewer)** | \`mcp__dgmo__render_diagram(dgmo, format:"png")\` → get temp path → \`open <path>\` |
149
+ | **View SVG in browser** | \`mcp__dgmo__render_diagram(dgmo, format:"svg")\` → write SVG to a temp \`.svg\` file → \`open <path>\` |
150
+ | **Save as PNG** | \`mcp__dgmo__render_diagram(dgmo, format:"png")\` → returns temp path; offer to copy to their preferred location. Or CLI: \`dgmo file.dgmo -o out.png\` |
151
+ | **Save as SVG** | \`mcp__dgmo__render_diagram(dgmo, format:"svg")\` returns SVG text — write it to the desired path. Or CLI: \`dgmo file.dgmo -o out.svg\` |
152
+ | **Shareable URL** | \`mcp__dgmo__share_diagram(dgmo)\` or CLI: \`dgmo file.dgmo -o url --copy\` |
153
+
154
+ **After creating a diagram, always present these options to the user** — don't just render silently and stop. A good response ends with something like: *"I've saved the file as \`diagram.dgmo\`. Want me to open it in the app, export it as a PNG, or generate a shareable link?"*
69
155
 
70
156
  ## CLI Reference
71
157
 
@@ -106,35 +192,306 @@ Key options:
106
192
  | \`quadrant\` | 2x2 positioning matrix |
107
193
  | \`sequence\` | Message / interaction flows |
108
194
  | \`flowchart\` | Decision trees, process flows |
195
+ | \`state\` | State machine / lifecycle |
109
196
  | \`class\` | UML class hierarchies |
110
197
  | \`er\` | Database schemas |
111
198
  | \`org\` | Hierarchical tree structures |
112
199
  | \`kanban\` | Task / workflow columns |
113
200
  | \`c4\` | System architecture (context → container → component → deployment) |
114
201
  | \`initiative-status\` | Project roadmap with dependency tracking |
202
+ | \`sitemap\` | Website / app navigation structure |
203
+ | \`infra\` | Infrastructure traffic flow with rps computation |
115
204
 
116
- ## Your Workflow
205
+ ## Key Syntax Patterns
117
206
 
118
- When the user asks you to create or edit a diagram:
207
+ ### Common to all diagrams
119
208
 
120
- 1. **Write or edit the \`.dgmo\` file** with the appropriate chart type and data.
121
- 2. **Render it** with \`dgmo <file>.dgmo -o <file>.png\` to verify it produces output without errors.
122
- 3. **Show the user** what was created and suggest a shareable URL with \`dgmo <file>.dgmo -o url --copy\` if they want to share it.
209
+ \`\`\`
210
+ chart: sequence // explicit type (optional auto-detected)
211
+ title: My Diagram
212
+ palette: catppuccin // override palette
123
213
 
124
- When the user asks for a **shareable link**, run:
214
+ // This is a comment (only // syntax — not #)
125
215
  \`\`\`
126
- dgmo <file>.dgmo -o url --copy
216
+
217
+ Inline colors on most elements: append \`(colorname)\` — e.g. \`North(red): 850\`, \`[Process(blue)]\`.
218
+ Named colors: \`red\`, \`orange\`, \`yellow\`, \`green\`, \`blue\`, \`purple\`, \`teal\`, \`cyan\`, \`gray\`.
219
+
220
+ ### sequence (most commonly used)
221
+
127
222
  \`\`\`
223
+ chart: sequence
224
+ title: Auth Flow
128
225
 
129
- ## Getting Syntax Help
226
+ // Participants auto-inferred, or declare explicitly:
227
+ User is an actor
228
+ API is a service
229
+ DB is a database
230
+
231
+ User -Login-> API
232
+ API -Find user-> DB
233
+ DB -user record-> API
130
234
 
131
- Run \`dgmo --chart-types\` to list types. For detailed syntax of a specific chart type, the best reference is the diagrammo.app documentation or existing \`.dgmo\` files in the project.
235
+ if credentials valid
236
+ API -200 OK + token-> User
237
+ else
238
+ API -401 Unauthorized-> User
239
+
240
+ == Logout ==
241
+
242
+ User -Logout-> API
243
+ API -Delete session-> DB
244
+ \`\`\`
245
+
246
+ - Sync: \`A -label-> B\` · Async: \`A ~label~> B\` · Unlabeled: \`A -> B\`
247
+ - Blocks: \`if\` / \`else\`, \`loop\`, \`parallel\` — closed by indentation (no \`end\` keyword)
248
+ - Notes: \`note on API: text\` or \`note: text\`
249
+ - Sections: \`== Title ==\`
250
+ - Groups: \`[Group Name]\` with indented participants
251
+
252
+ ### flowchart
253
+
254
+ \`\`\`
255
+ (Start) -> <Valid Input?>
256
+ -yes-> [Process Data] -> (Done)
257
+ -no-> /Get Input/ -> <Valid Input?>
258
+ \`\`\`
259
+
260
+ Shapes: \`(oval)\` \`[rect]\` \`<diamond>\` \`/parallelogram/\` \`[[subroutine]]\` \`[document~]\`
261
+
262
+ ### bar / line / pie (data charts)
263
+
264
+ \`\`\`
265
+ // bar
266
+ title: Revenue by Region
267
+ series: Revenue
268
+ North: 850
269
+ South: 620
270
+
271
+ // line (multi-series)
272
+ series: Sales(red), Costs(blue)
273
+ Q1: 100, 50
274
+ Q2: 120, 55
275
+
276
+ // pie
277
+ chart: pie
278
+ labels: percent
279
+ Company A: 40
280
+ Company B: 35
281
+ \`\`\`
282
+
283
+ ### er
284
+
285
+ \`\`\`
286
+ users
287
+ id: int [pk]
288
+ email: varchar [unique]
289
+ 1-writes-* posts
290
+
291
+ posts
292
+ id: int [pk]
293
+ author_id: int [fk]
294
+ \`\`\`
295
+
296
+ ### org
297
+
298
+ \`\`\`
299
+ CEO
300
+ VP Engineering
301
+ [Platform Team]
302
+ Lead
303
+ Dev 1
304
+ Dev 2
305
+ VP Marketing
306
+ \`\`\`
307
+
308
+ ### infra
309
+
310
+ \`\`\`
311
+ chart: infra
312
+ edge
313
+ rps: 10000
314
+ -> CDN
315
+
316
+ CDN
317
+ cache-hit: 80%
318
+ -> API
319
+
320
+ API
321
+ instances: 3
322
+ max-rps: 500
323
+ latency-ms: 45
324
+ \`\`\`
325
+
326
+ ## Anti-Patterns
327
+
328
+ \`\`\`
329
+ # comment ❌ use // comment
330
+ async A -> B: msg ❌ use A ~msg~> B
331
+ A <- B ❌ left-pointing arrows removed — use B -> A
332
+ parallel else ❌ not supported — use separate parallel blocks
333
+ == Foo(#ff0000) == ❌ hex colors not supported — use named colors: == Foo(red) ==
334
+ A -routes to /api-> B ❌ -> inside a label is ambiguous — rephrase the label
335
+ end ❌ not needed — indentation closes blocks in sequence diagrams
336
+ \`\`\`
132
337
 
133
338
  ## Tips
134
339
 
135
- - Default theme is \`light\` and default palette is \`nord\` — ask the user if they have a preference before rendering a final export.
136
- - For C4 diagrams, use \`--c4-level\` to drill from context → containers → components → deployment.
137
- - Stdin mode is useful for quick one-off renders: \`echo "..." | dgmo -o out.png\`
340
+ - Default theme: \`light\`, default palette: \`nord\` — ask the user their preference before a final export.
341
+ - Stdin mode for quick renders: \`echo "..." | dgmo -o out.png\`
342
+ - For C4, \`--c4-level\` drills from context containers components deployment.
343
+ - When auto-detection picks the wrong chart type, add an explicit \`chart:\` directive.
344
+ - \`mcp__dgmo__preview_diagram\` accepts multiple diagrams at once — useful for showing variants side by side.
345
+ `;
346
+
347
+ const CODEX_AGENTS_CONTENT = `# DGMO Diagram Language — Codex Integration
348
+
349
+ Use dgmo tools to create, render, and share diagrams. dgmo is a text-based diagram markup language that renders to SVG/PNG.
350
+
351
+ ## Quick setup
352
+
353
+ If the MCP server is not yet configured:
354
+
355
+ \`\`\`bash
356
+ dgmo --install-codex-integration
357
+ \`\`\`
358
+
359
+ This installs the MCP server and writes the dgmo config to \`.codex/config.toml\`. Restart Codex to activate.
360
+
361
+ ## MCP Tools
362
+
363
+ When the \`dgmo\` MCP server is configured, use these tools directly:
364
+ - \`preview_diagram\` — renders diagram(s) and opens a live HTML preview in the browser (default for showing diagrams)
365
+ - \`render_diagram\` — renders to PNG or SVG, returns file path
366
+ - \`share_diagram\` — creates a shareable diagrammo.app URL
367
+ - \`open_in_app\` — opens diagram in Diagrammo desktop app (macOS)
368
+ - \`list_chart_types\` — lists all 32 supported chart types with descriptions
369
+ - \`get_language_reference\` — fetches full syntax for any chart type (call this before generating an unfamiliar chart type)
370
+ - \`generate_report\` — renders multiple diagrams into an HTML report with table of contents
371
+
372
+ ## When to use dgmo
373
+
374
+ - Architecture diagrams, sequence diagrams, flowcharts
375
+ - Data charts (bar, line, pie, scatter, heatmap, etc.)
376
+ - ER diagrams, class diagrams, org charts
377
+ - Project roadmaps, kanban boards, timelines
378
+
379
+ ## Quick syntax reference
380
+
381
+ ### Sequence diagram
382
+ \`\`\`
383
+ chart: sequence
384
+ title: Auth Flow
385
+
386
+ User -Login-> API
387
+ API -Find user-> DB
388
+ DB -user-> API
389
+ if valid
390
+ API -200 OK-> User
391
+ else
392
+ API -401-> User
393
+ \`\`\`
394
+
395
+ ### Flowchart
396
+ \`\`\`
397
+ chart: flowchart
398
+ title: Process
399
+
400
+ (Start) -> <Valid?>
401
+ -yes-> [Process] -> (Done)
402
+ -no-> /Get Input/ -> <Valid?>
403
+ \`\`\`
404
+
405
+ ### Bar chart
406
+ \`\`\`
407
+ chart: bar
408
+ title: Revenue
409
+ series: USD
410
+
411
+ North: 850
412
+ South: 620
413
+ East: 1100
414
+ \`\`\`
415
+
416
+ ### ER diagram
417
+ \`\`\`
418
+ chart: er
419
+ title: Schema
420
+
421
+ users
422
+ id: int [pk]
423
+ email: varchar [unique]
424
+
425
+ posts
426
+ id: int [pk]
427
+ user_id: int [fk]
428
+
429
+ users 1--* posts : writes
430
+ \`\`\`
431
+
432
+ ### Org chart
433
+ \`\`\`
434
+ chart: org
435
+
436
+ CEO
437
+ VP Engineering
438
+ Team Lead A
439
+ Team Lead B
440
+ VP Marketing
441
+ \`\`\`
442
+
443
+ ### Infra chart
444
+ \`\`\`
445
+ chart: infra
446
+ direction: LR
447
+
448
+ edge
449
+ rps: 10000
450
+ -> CDN
451
+
452
+ CDN
453
+ cache-hit: 80%
454
+ -> LB
455
+
456
+ LB
457
+ -> API | split: 70%
458
+ -> Web | split: 30%
459
+
460
+ API
461
+ instances: 3
462
+ max-rps: 500
463
+ latency-ms: 45
464
+ \`\`\`
465
+
466
+ ## All 32 chart types
467
+
468
+ bar, line, multi-line, area, pie, doughnut, radar, polar-area, bar-stacked, scatter, sankey, chord, function, heatmap, funnel, slope, wordcloud, arc, timeline, venn, quadrant, sequence, flowchart, state, class, er, org, kanban, c4, initiative-status, sitemap, infra
469
+
470
+ ## Common patterns
471
+
472
+ - \`chart: type\` — explicit chart type (auto-detected if unambiguous)
473
+ - \`title: text\` — diagram title
474
+ - \`// comment\` — only \`//\` comments (not \`#\`)
475
+ - \`(colorname)\` — inline colors: \`Label(red): 100\`
476
+ - \`series: A(red), B(blue)\` — multi-series with colors
477
+
478
+ ## Rendering via CLI
479
+
480
+ \`\`\`bash
481
+ dgmo file.dgmo -o output.svg # SVG
482
+ dgmo file.dgmo -o url # shareable link
483
+ dgmo file.dgmo --json # structured JSON output
484
+ \`\`\`
485
+
486
+ ## Mistakes to avoid
487
+
488
+ - Don't use \`#\` for comments — use \`//\`
489
+ - Don't use \`end\` to close sequence blocks — indentation closes them
490
+ - Don't use hex colors in section headers — use named colors
491
+ - Don't forget \`chart:\` directive when content is ambiguous
492
+ - Sequence arrows: \`->\` (sync), \`~>\` (async) — always left-to-right
493
+
494
+ Full reference: call \`get_language_reference\` MCP tool or visit diagrammo.app/docs
138
495
  `;
139
496
 
140
497
  function printHelp(): void {
@@ -158,7 +515,14 @@ Options:
158
515
  --copy Copy URL to clipboard (only with -o url)
159
516
  --json Output structured JSON to stdout
160
517
  --chart-types List all supported chart types
161
- --install-claude-skill Install the dgmo Claude Code skill to ~/.claude/commands/
518
+ --install-claude-code-integration
519
+ Full Claude Code setup: install the /dgmo skill and configure
520
+ the dgmo MCP server — installs @diagrammo/dgmo-mcp if needed,
521
+ then writes .mcp.json (project) or ~/.claude/settings.json (global)
522
+ --install-claude-skill Install only the /dgmo skill to ~/.claude/commands/dgmo.md
523
+ --install-codex-integration
524
+ Full Codex CLI setup: write AGENTS.md to the project and configure
525
+ the dgmo MCP server in .codex/config.toml (project) or ~/.codex/config.toml (global)
162
526
  --help Show this help
163
527
  --version Show version`);
164
528
  }
@@ -182,6 +546,8 @@ function parseArgs(argv: string[]): {
182
546
  json: boolean;
183
547
  chartTypes: boolean;
184
548
  installClaudeSkill: boolean;
549
+ installClaudeCodeIntegration: boolean;
550
+ installCodexIntegration: boolean;
185
551
  c4Level: 'context' | 'containers' | 'components' | 'deployment';
186
552
  c4System: string | undefined;
187
553
  c4Container: string | undefined;
@@ -199,6 +565,8 @@ function parseArgs(argv: string[]): {
199
565
  json: false,
200
566
  chartTypes: false,
201
567
  installClaudeSkill: false,
568
+ installClaudeCodeIntegration: false,
569
+ installCodexIntegration: false,
202
570
  c4Level: 'context' as 'context' | 'containers' | 'components' | 'deployment',
203
571
  c4System: undefined as string | undefined,
204
572
  c4Container: undefined as string | undefined,
@@ -268,9 +636,15 @@ function parseArgs(argv: string[]): {
268
636
  } else if (arg === '--chart-types') {
269
637
  result.chartTypes = true;
270
638
  i++;
639
+ } else if (arg === '--install-claude-code-integration') {
640
+ result.installClaudeCodeIntegration = true;
641
+ i++;
271
642
  } else if (arg === '--install-claude-skill') {
272
643
  result.installClaudeSkill = true;
273
644
  i++;
645
+ } else if (arg === '--install-codex-integration') {
646
+ result.installCodexIntegration = true;
647
+ i++;
274
648
  } else if (arg === '--copy') {
275
649
  result.copy = true;
276
650
  i++;
@@ -374,6 +748,92 @@ async function main(): Promise<void> {
374
748
  return;
375
749
  }
376
750
 
751
+ if (opts.installClaudeCodeIntegration) {
752
+ const claudeDir = join(homedir(), '.claude');
753
+ if (!existsSync(claudeDir)) {
754
+ console.error('~/.claude directory not found.');
755
+ console.error('Install Claude Code first: https://claude.ai/code');
756
+ process.exit(1);
757
+ }
758
+
759
+ function ask(prompt: string): Promise<string> {
760
+ return new Promise((resolve) => {
761
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
762
+ rl.question(prompt, (answer) => { rl.close(); resolve(answer); });
763
+ });
764
+ }
765
+
766
+ // --- Step 1: Install skill ---
767
+ const commandsDir = join(claudeDir, 'commands');
768
+ const skillPath = join(commandsDir, 'dgmo.md');
769
+ const skillExists = existsSync(skillPath);
770
+ let installSkill = true;
771
+ if (skillExists) {
772
+ const ans = await ask('~/.claude/commands/dgmo.md already exists. Overwrite? [y/N] ');
773
+ installSkill = ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
774
+ }
775
+ if (installSkill) {
776
+ if (!existsSync(commandsDir)) mkdirSync(commandsDir, { recursive: true });
777
+ writeFileSync(skillPath, CLAUDE_SKILL_CONTENT, 'utf-8');
778
+ console.log('✓ Skill installed: ~/.claude/commands/dgmo.md');
779
+ } else {
780
+ console.log(' Skipped skill install.');
781
+ }
782
+
783
+ // --- Step 2: Check / install dgmo-mcp binary ---
784
+ let dgmoMcpInstalled = false;
785
+ try { execSync('which dgmo-mcp', { stdio: 'pipe' }); dgmoMcpInstalled = true; } catch { /* not found */ }
786
+ if (!dgmoMcpInstalled) {
787
+ const ans = await ask('\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] ');
788
+ const yes = ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
789
+ if (yes) {
790
+ console.log('Installing @diagrammo/dgmo-mcp...');
791
+ execSync('npm install -g @diagrammo/dgmo-mcp', { stdio: 'inherit' });
792
+ console.log('✓ @diagrammo/dgmo-mcp installed');
793
+ } else {
794
+ console.log(' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp');
795
+ }
796
+ } else {
797
+ console.log('✓ dgmo-mcp already installed');
798
+ }
799
+
800
+ // --- Step 3: Configure MCP server ---
801
+ console.log('\nWhere should the MCP server be configured?');
802
+ console.log(' 1) This project only — write .mcp.json here [default]');
803
+ console.log(' 2) Globally — add to ~/.claude/settings.json (works in all projects)');
804
+ const scopeAns = await ask('\nChoice [1]: ');
805
+ const useGlobal = scopeAns.trim() === '2';
806
+ const mcpEntry = { command: 'dgmo-mcp' };
807
+
808
+ if (useGlobal) {
809
+ const settingsPath = join(claudeDir, 'settings.json');
810
+ let settings: Record<string, unknown> = {};
811
+ if (existsSync(settingsPath)) {
812
+ try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { /* use empty */ }
813
+ }
814
+ const mcpServers = (settings.mcpServers as Record<string, unknown> | undefined) ?? {};
815
+ mcpServers['dgmo'] = mcpEntry;
816
+ settings.mcpServers = mcpServers;
817
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
818
+ console.log('✓ MCP server added to ~/.claude/settings.json');
819
+ } else {
820
+ const mcpPath = join(process.cwd(), '.mcp.json');
821
+ let mcp: Record<string, unknown> = {};
822
+ if (existsSync(mcpPath)) {
823
+ try { mcp = JSON.parse(readFileSync(mcpPath, 'utf-8')); } catch { /* use empty */ }
824
+ }
825
+ const mcpServers = (mcp.mcpServers as Record<string, unknown> | undefined) ?? {};
826
+ mcpServers['dgmo'] = mcpEntry;
827
+ mcp.mcpServers = mcpServers;
828
+ writeFileSync(mcpPath, JSON.stringify(mcp, null, 2) + '\n', 'utf-8');
829
+ console.log(`✓ MCP server configured: ${join(process.cwd(), '.mcp.json')}`);
830
+ }
831
+
832
+ console.log('\nRestart Claude Code to activate the MCP server.');
833
+ console.log('Then type /dgmo in any session to start creating diagrams.');
834
+ return;
835
+ }
836
+
377
837
  if (opts.installClaudeSkill) {
378
838
  const claudeDir = join(homedir(), '.claude');
379
839
  if (!existsSync(claudeDir)) {
@@ -410,6 +870,95 @@ async function main(): Promise<void> {
410
870
  return;
411
871
  }
412
872
 
873
+ if (opts.installCodexIntegration) {
874
+ // Validate Codex CLI is installed
875
+ try { execSync('which codex', { stdio: 'pipe' }); } catch {
876
+ console.error('codex not found. Install Codex CLI first: https://openai.com/codex');
877
+ process.exit(1);
878
+ }
879
+
880
+ const ask = (prompt: string): Promise<string> =>
881
+ new Promise((resolve) => {
882
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
883
+ rl.question(prompt, (answer) => { rl.close(); resolve(answer); });
884
+ });
885
+
886
+ // Check / install dgmo-mcp binary
887
+ let dgmoMcpInstalled = false;
888
+ try { execSync('which dgmo-mcp', { stdio: 'pipe' }); dgmoMcpInstalled = true; } catch { /* not found */ }
889
+ if (!dgmoMcpInstalled) {
890
+ const ans = await ask('\ndgmo-mcp not found. Install @diagrammo/dgmo-mcp globally now? [Y/n] ');
891
+ const yes = ans === '' || ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
892
+ if (yes) {
893
+ console.log('Installing @diagrammo/dgmo-mcp...');
894
+ try {
895
+ execSync('npm install -g @diagrammo/dgmo-mcp', { stdio: 'inherit' });
896
+ console.log('✓ @diagrammo/dgmo-mcp installed');
897
+ } catch {
898
+ console.error('Error: Failed to install @diagrammo/dgmo-mcp.');
899
+ console.error('Try manually: npm install -g @diagrammo/dgmo-mcp');
900
+ }
901
+ } else {
902
+ console.log(' Skipped. Install later with: npm install -g @diagrammo/dgmo-mcp');
903
+ }
904
+ } else {
905
+ console.log('✓ dgmo-mcp already installed');
906
+ }
907
+
908
+ // Configure MCP server
909
+ console.log('\nWhere should the MCP server be configured?');
910
+ console.log(' 1) This project only — write .codex/config.toml here [default]');
911
+ console.log(' 2) Globally — add to ~/.codex/config.toml (works in all projects)');
912
+ const scopeAns = await ask('\nChoice [1]: ');
913
+ if (scopeAns.trim() !== '' && scopeAns.trim() !== '1' && scopeAns.trim() !== '2') {
914
+ console.log(` Unrecognized input "${scopeAns.trim()}", defaulting to option 1.`);
915
+ }
916
+ const useGlobal = scopeAns.trim() === '2';
917
+ const tomlEntry = '[mcp_servers.dgmo]\ncommand = ["dgmo-mcp"]\n';
918
+
919
+ if (useGlobal) {
920
+ const configPath = join(homedir(), '.codex', 'config.toml');
921
+ mkdirSync(join(homedir(), '.codex'), { recursive: true });
922
+ const existing = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
923
+ if (existing.includes('[mcp_servers.dgmo]')) {
924
+ console.log('✓ MCP server already configured in ~/.codex/config.toml');
925
+ } else {
926
+ const separator = existing.length > 0 ? '\n' : '';
927
+ writeFileSync(configPath, existing + separator + tomlEntry, 'utf-8');
928
+ console.log('✓ MCP server added to ~/.codex/config.toml');
929
+ }
930
+ } else {
931
+ const codexDir = join(process.cwd(), '.codex');
932
+ const configPath = join(codexDir, 'config.toml');
933
+ mkdirSync(codexDir, { recursive: true });
934
+ const existing = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : '';
935
+ if (existing.includes('[mcp_servers.dgmo]')) {
936
+ console.log(`✓ MCP server already configured in .codex/config.toml`);
937
+ } else {
938
+ const separator = existing.length > 0 ? '\n' : '';
939
+ writeFileSync(configPath, existing + separator + tomlEntry, 'utf-8');
940
+ console.log(`✓ MCP server configured: ${configPath}`);
941
+ }
942
+ }
943
+
944
+ // Write AGENTS.md
945
+ const agentsPath = join(process.cwd(), 'AGENTS.md');
946
+ let writeAgents = true;
947
+ if (existsSync(agentsPath)) {
948
+ const ans = await ask('\nAGENTS.md already exists. Overwrite? [y/N] ');
949
+ writeAgents = ans.toLowerCase() === 'y' || ans.toLowerCase() === 'yes';
950
+ }
951
+ if (writeAgents) {
952
+ writeFileSync(agentsPath, CODEX_AGENTS_CONTENT, 'utf-8');
953
+ console.log(`✓ AGENTS.md written to: ${agentsPath}`);
954
+ } else {
955
+ console.log(' Skipped AGENTS.md.');
956
+ }
957
+
958
+ console.log('\nRestart Codex to activate the MCP server.');
959
+ return;
960
+ }
961
+
413
962
  // Determine input source
414
963
  let content: string;
415
964
  let inputBasename: string | undefined;