agentic-mermaid 0.1.0 → 0.1.2

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 (333) hide show
  1. package/CHANGELOG.md +149 -4
  2. package/LICENSES/Apache-2.0.txt +202 -0
  3. package/README.md +25 -32
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/assets/fonts/FONT-LICENSES.md +9 -5
  6. package/assets/fonts/Inter-Bold.ttf +0 -0
  7. package/assets/fonts/Inter-Medium.ttf +0 -0
  8. package/assets/fonts/Inter-Regular.ttf +0 -0
  9. package/assets/fonts/Inter-SemiBold.ttf +0 -0
  10. package/dist/agent-core.d.ts +463 -0
  11. package/dist/agent-core.js +397 -0
  12. package/dist/agent.d.ts +81 -1822
  13. package/dist/agent.js +336 -36839
  14. package/dist/agentic-mermaid-mcp.js +7 -37908
  15. package/dist/am.js +33638 -36261
  16. package/dist/chunk-4QECACIA.js +4702 -0
  17. package/dist/chunk-CDPKJ2BQ.js +37 -0
  18. package/dist/chunk-QKDLMOJJ.js +3487 -0
  19. package/dist/chunk-WI35L7IR.js +615 -0
  20. package/dist/chunk-WN3YDOBG.js +149 -0
  21. package/dist/chunk-ZYMMKQ3I.js +62637 -0
  22. package/dist/index-D54dqSdC.d.ts +6777 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +310 -32836
  25. package/dist/mcp-cli-SBQSTJFC.js +17 -0
  26. package/docs/README.md +14 -6
  27. package/docs/schemas/style-spec.schema.json +1221 -30
  28. package/examples/styles/catalog.json +54 -0
  29. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  30. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  31. package/examples/styles/cupertino-prototype.mmd +10 -0
  32. package/examples/styles/cupertino-prototype.style.json +63 -0
  33. package/examples/styles/mid-century-report.style.json +2 -2
  34. package/examples/styles/star-chart-atlas.style.json +2 -1
  35. package/examples/styles/transit-route-map.style.json +2 -2
  36. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  37. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  38. package/package.json +70 -43
  39. package/server.json +41 -0
  40. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  41. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  42. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  43. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  44. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  45. package/AGENT_NATIVE.md +0 -602
  46. package/Instructions_for_agents.md +0 -83
  47. package/TODO.md +0 -662
  48. package/assets/hero.png +0 -0
  49. package/dist/index-x2Cj1dVv.d.ts +0 -1089
  50. package/docs/agent-api-cookbook.md +0 -308
  51. package/docs/agent-mutation-policy.md +0 -104
  52. package/docs/agent-workflow-examples.md +0 -46
  53. package/docs/api.md +0 -203
  54. package/docs/ascii.md +0 -103
  55. package/docs/assets/improvements/box-start-connector.png +0 -0
  56. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  57. package/docs/assets/improvements/er-content-loss.png +0 -0
  58. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  59. package/docs/assets/improvements/gantt-family.png +0 -0
  60. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  61. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  62. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  63. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  64. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  65. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  66. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  67. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  68. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  69. package/docs/comparison.md +0 -94
  70. package/docs/config.md +0 -105
  71. package/docs/contributing/adding-diagram-types.md +0 -144
  72. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  73. package/docs/contributing/diagram-family-citizenship.md +0 -82
  74. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  75. package/docs/contributing/lessons-learned.md +0 -276
  76. package/docs/contributing/releasing.md +0 -71
  77. package/docs/contributing/visual-review-evidence.md +0 -53
  78. package/docs/custom-style-cookbook.md +0 -154
  79. package/docs/design/families/README.md +0 -26
  80. package/docs/design/families/architecture-beta.md +0 -48
  81. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  82. package/docs/design/families/gantt-research.md +0 -137
  83. package/docs/design/families/gantt.md +0 -329
  84. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  85. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  86. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  87. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  88. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  89. package/docs/design/families/journey-migration-parity.md +0 -433
  90. package/docs/design/families/journey-usage-research.md +0 -423
  91. package/docs/design/families/journey.md +0 -125
  92. package/docs/design/families/xychart.md +0 -85
  93. package/docs/design/system/README.md +0 -45
  94. package/docs/design/system/abstraction-audit.md +0 -224
  95. package/docs/design/system/abstraction-recommendations.md +0 -655
  96. package/docs/design/system/architecture.mmd +0 -29
  97. package/docs/design/system/architecture.svg +0 -137
  98. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  99. package/docs/design/system/layout-rubric.md +0 -138
  100. package/docs/design/system/route-contracts.md +0 -848
  101. package/docs/design/system/source-preservation-ladder.md +0 -52
  102. package/docs/design/system/styles-rollout.md +0 -216
  103. package/docs/design/system/ugly-layouts.md +0 -119
  104. package/docs/diagram-families.md +0 -193
  105. package/docs/features.md +0 -147
  106. package/docs/fork-differences.md +0 -130
  107. package/docs/getting-started.md +0 -175
  108. package/docs/issue-derived-test-cases.md +0 -156
  109. package/docs/layout-characterization/README.md +0 -245
  110. package/docs/layout-characterization/contact-sheet-families.md +0 -496
  111. package/docs/layout-characterization/contact-sheet.md +0 -638
  112. package/docs/layout-characterization/properties.md +0 -281
  113. package/docs/layout-characterization/visual-quality.md +0 -160
  114. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  115. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  116. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  117. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  118. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  119. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -118
  120. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  121. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  122. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  123. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  124. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  125. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  126. package/docs/mcp-code-mode-rationale.md +0 -101
  127. package/docs/mcp-http-transport.md +0 -223
  128. package/docs/mermaid-layout-complaints.md +0 -837
  129. package/docs/mutation-testing.md +0 -206
  130. package/docs/project/divergences.md +0 -98
  131. package/docs/project/dogfooding-docs-strategy.md +0 -66
  132. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  133. package/docs/project/lessons-learned.md +0 -1019
  134. package/docs/project/remove-role-styling-plan.md +0 -176
  135. package/docs/quality.md +0 -212
  136. package/docs/react.md +0 -97
  137. package/docs/style-authoring.md +0 -133
  138. package/docs/testing-strategy.md +0 -335
  139. package/docs/theming.md +0 -162
  140. package/examples/agent-improve-auth-flow.ts +0 -206
  141. package/examples/agent-loop.ts +0 -53
  142. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  143. package/llms.txt +0 -104
  144. package/skill-evals/README.md +0 -77
  145. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  146. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  147. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  148. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  149. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  150. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  151. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  152. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  153. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  154. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  155. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  156. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  157. package/skill-evals/shared-benchmark.json +0 -510
  158. package/src/agent/analyze.ts +0 -157
  159. package/src/agent/apply.ts +0 -146
  160. package/src/agent/architecture-body.ts +0 -458
  161. package/src/agent/certificates.ts +0 -110
  162. package/src/agent/class-body.ts +0 -319
  163. package/src/agent/core.ts +0 -207
  164. package/src/agent/create.ts +0 -106
  165. package/src/agent/describe.ts +0 -364
  166. package/src/agent/er-body.ts +0 -224
  167. package/src/agent/facts.ts +0 -337
  168. package/src/agent/families-builtin.ts +0 -934
  169. package/src/agent/families.ts +0 -232
  170. package/src/agent/family-layouts.ts +0 -826
  171. package/src/agent/flowchart-body.ts +0 -372
  172. package/src/agent/flowchart-unsupported.ts +0 -243
  173. package/src/agent/gantt-body.ts +0 -495
  174. package/src/agent/index.ts +0 -10
  175. package/src/agent/journey-body.ts +0 -414
  176. package/src/agent/label-metrics.ts +0 -28
  177. package/src/agent/layout-to-rendered.ts +0 -63
  178. package/src/agent/mutate.ts +0 -97
  179. package/src/agent/mutation-ops.ts +0 -51
  180. package/src/agent/op-schema.ts +0 -439
  181. package/src/agent/parse.ts +0 -223
  182. package/src/agent/pie-body.ts +0 -270
  183. package/src/agent/png.ts +0 -117
  184. package/src/agent/quadrant-body.ts +0 -336
  185. package/src/agent/quality.ts +0 -363
  186. package/src/agent/readability-audit.ts +0 -92
  187. package/src/agent/rendered-route-audit.ts +0 -61
  188. package/src/agent/sequence-body.ts +0 -345
  189. package/src/agent/serialize.ts +0 -214
  190. package/src/agent/state-body.ts +0 -589
  191. package/src/agent/structural-count.ts +0 -150
  192. package/src/agent/timeline-body.ts +0 -280
  193. package/src/agent/trace-log.ts +0 -43
  194. package/src/agent/types.ts +0 -979
  195. package/src/agent/verify.ts +0 -571
  196. package/src/agent/xychart-body.ts +0 -472
  197. package/src/architecture/config.ts +0 -282
  198. package/src/architecture/layout.ts +0 -496
  199. package/src/architecture/parser.ts +0 -375
  200. package/src/architecture/renderer.ts +0 -611
  201. package/src/architecture/types.ts +0 -113
  202. package/src/ascii/ansi.ts +0 -423
  203. package/src/ascii/architecture.ts +0 -210
  204. package/src/ascii/canvas.ts +0 -443
  205. package/src/ascii/class-diagram.ts +0 -697
  206. package/src/ascii/converter.ts +0 -475
  207. package/src/ascii/draw.ts +0 -1693
  208. package/src/ascii/edge-bundling.ts +0 -328
  209. package/src/ascii/edge-routing.ts +0 -330
  210. package/src/ascii/er-diagram.ts +0 -439
  211. package/src/ascii/gantt.ts +0 -276
  212. package/src/ascii/grid.ts +0 -747
  213. package/src/ascii/index.ts +0 -196
  214. package/src/ascii/journey.ts +0 -189
  215. package/src/ascii/meta.ts +0 -244
  216. package/src/ascii/multiline-utils.ts +0 -80
  217. package/src/ascii/pathfinder.ts +0 -301
  218. package/src/ascii/pie.ts +0 -67
  219. package/src/ascii/quadrant.ts +0 -158
  220. package/src/ascii/reverse.ts +0 -216
  221. package/src/ascii/sequence.ts +0 -499
  222. package/src/ascii/shapes/circle.ts +0 -27
  223. package/src/ascii/shapes/corners.ts +0 -143
  224. package/src/ascii/shapes/diamond.ts +0 -27
  225. package/src/ascii/shapes/hexagon.ts +0 -27
  226. package/src/ascii/shapes/index.ts +0 -106
  227. package/src/ascii/shapes/rectangle.ts +0 -168
  228. package/src/ascii/shapes/rounded.ts +0 -27
  229. package/src/ascii/shapes/special.ts +0 -332
  230. package/src/ascii/shapes/stadium.ts +0 -110
  231. package/src/ascii/shapes/state.ts +0 -192
  232. package/src/ascii/shapes/types.ts +0 -73
  233. package/src/ascii/timeline.ts +0 -128
  234. package/src/ascii/types.ts +0 -312
  235. package/src/ascii/validate.ts +0 -120
  236. package/src/ascii/width.ts +0 -81
  237. package/src/ascii/xychart.ts +0 -919
  238. package/src/browser.ts +0 -29
  239. package/src/class/layout.ts +0 -240
  240. package/src/class/parser.ts +0 -332
  241. package/src/class/renderer.ts +0 -638
  242. package/src/class/types.ts +0 -129
  243. package/src/cli/agent-instructions.ts +0 -1
  244. package/src/cli/am-bin.ts +0 -6
  245. package/src/cli/exit-codes.ts +0 -18
  246. package/src/cli/index.ts +0 -1117
  247. package/src/cli/init-agent.ts +0 -147
  248. package/src/color-resolver.ts +0 -152
  249. package/src/elk-instance.ts +0 -114
  250. package/src/er/layout.ts +0 -187
  251. package/src/er/parser.ts +0 -226
  252. package/src/er/renderer.ts +0 -792
  253. package/src/er/types.ts +0 -99
  254. package/src/font-manifest.ts +0 -27
  255. package/src/gantt/layout.ts +0 -365
  256. package/src/gantt/parser.ts +0 -282
  257. package/src/gantt/pipeline.ts +0 -27
  258. package/src/gantt/renderer.ts +0 -414
  259. package/src/gantt/schedule.ts +0 -513
  260. package/src/gantt/types.ts +0 -255
  261. package/src/index.ts +0 -368
  262. package/src/journey/layout.ts +0 -520
  263. package/src/journey/parser.ts +0 -218
  264. package/src/journey/renderer.ts +0 -811
  265. package/src/journey/types.ts +0 -144
  266. package/src/layout/geometry.ts +0 -182
  267. package/src/layout/pass.ts +0 -142
  268. package/src/layout/passes/index.ts +0 -3916
  269. package/src/layout-engine.ts +0 -1565
  270. package/src/layout-rubric.ts +0 -659
  271. package/src/mcp/artifacts.ts +0 -137
  272. package/src/mcp/dynamic-harness.ts +0 -31
  273. package/src/mcp/dynamic-modules.d.ts +0 -7
  274. package/src/mcp/facade.ts +0 -608
  275. package/src/mcp/harness-runtime.ts +0 -203
  276. package/src/mcp/hosted-server.ts +0 -468
  277. package/src/mcp/mcp-bin.ts +0 -3
  278. package/src/mcp/mcp-cli.ts +0 -82
  279. package/src/mcp/protocol.ts +0 -13
  280. package/src/mcp/sandbox.ts +0 -195
  281. package/src/mcp/sdk-decl.ts +0 -387
  282. package/src/mcp/server.ts +0 -362
  283. package/src/mcp/tool-surface.ts +0 -146
  284. package/src/mermaid-source.ts +0 -655
  285. package/src/multiline-utils.ts +0 -228
  286. package/src/parser.ts +0 -1031
  287. package/src/pie/layout.ts +0 -168
  288. package/src/pie/parser.ts +0 -136
  289. package/src/pie/renderer.ts +0 -234
  290. package/src/pie/types.ts +0 -82
  291. package/src/quadrant/layout.ts +0 -191
  292. package/src/quadrant/parser.ts +0 -183
  293. package/src/quadrant/renderer.ts +0 -322
  294. package/src/quadrant/types.ts +0 -113
  295. package/src/render-family-hooks.ts +0 -244
  296. package/src/renderer.ts +0 -1099
  297. package/src/route-contracts.ts +0 -2723
  298. package/src/scene/backend.ts +0 -76
  299. package/src/scene/fidelity.ts +0 -183
  300. package/src/scene/hybrid-backend.ts +0 -174
  301. package/src/scene/ir.ts +0 -181
  302. package/src/scene/marks.ts +0 -127
  303. package/src/scene/rough-backend.ts +0 -378
  304. package/src/scene/seed.ts +0 -46
  305. package/src/scene/style-registry.ts +0 -556
  306. package/src/sequence/layout.ts +0 -456
  307. package/src/sequence/parser.ts +0 -255
  308. package/src/sequence/renderer.ts +0 -604
  309. package/src/sequence/types.ts +0 -154
  310. package/src/shape-clipping.ts +0 -351
  311. package/src/shared/accessibility-directives.ts +0 -22
  312. package/src/shared/batched.ts +0 -61
  313. package/src/shared/color-math.ts +0 -72
  314. package/src/shared/svg-a11y.ts +0 -29
  315. package/src/shared/syntax-error.ts +0 -17
  316. package/src/shared/unicode-ranges.ts +0 -135
  317. package/src/styles.ts +0 -318
  318. package/src/svg-paths.ts +0 -28
  319. package/src/text-metrics.ts +0 -248
  320. package/src/theme.ts +0 -639
  321. package/src/timeline/layout.ts +0 -381
  322. package/src/timeline/parser.ts +0 -215
  323. package/src/timeline/renderer.ts +0 -538
  324. package/src/timeline/types.ts +0 -105
  325. package/src/types.ts +0 -454
  326. package/src/website-worker-modules.d.ts +0 -18
  327. package/src/xychart/axis-utils.ts +0 -109
  328. package/src/xychart/colors.ts +0 -124
  329. package/src/xychart/config.ts +0 -88
  330. package/src/xychart/layout.ts +0 -656
  331. package/src/xychart/parser.ts +0 -504
  332. package/src/xychart/renderer.ts +0 -640
  333. package/src/xychart/types.ts +0 -282
@@ -1,113 +0,0 @@
1
- // ============================================================================
2
- // Architecture diagram types
3
- //
4
- // Parsed representation for Mermaid `architecture-beta` diagrams plus the
5
- // positioned structures used by the SVG renderer.
6
- // ============================================================================
7
-
8
- import type { Point, PositionedDiagram } from '../types.ts'
9
-
10
- export type ArchitectureSide = 'L' | 'R' | 'T' | 'B'
11
- export type ArchitectureEndpointBoundary = 'item' | 'group'
12
-
13
- export interface ArchitectureChildRef {
14
- kind: 'group' | 'service' | 'junction'
15
- id: string
16
- }
17
-
18
- export interface ArchitectureGroup {
19
- id: string
20
- label: string
21
- icon?: string
22
- parentId?: string
23
- children: ArchitectureChildRef[]
24
- }
25
-
26
- export interface ArchitectureService {
27
- id: string
28
- label: string
29
- icon?: string
30
- parentId?: string
31
- }
32
-
33
- export interface ArchitectureJunction {
34
- id: string
35
- parentId?: string
36
- }
37
-
38
- export interface ArchitectureEndpoint {
39
- id: string
40
- side: ArchitectureSide
41
- boundary: ArchitectureEndpointBoundary
42
- }
43
-
44
- export interface ArchitectureEdge {
45
- source: ArchitectureEndpoint
46
- target: ArchitectureEndpoint
47
- label?: string
48
- hasArrowStart: boolean
49
- hasArrowEnd: boolean
50
- }
51
-
52
- export interface ArchitectureDiagram {
53
- groups: ArchitectureGroup[]
54
- services: ArchitectureService[]
55
- junctions: ArchitectureJunction[]
56
- edges: ArchitectureEdge[]
57
- rootChildren: ArchitectureChildRef[]
58
- accessibilityTitle?: string
59
- accessibilityDescription?: string
60
- }
61
-
62
- export interface PositionedArchitectureGroup {
63
- id: string
64
- label: string
65
- icon?: string
66
- parentId?: string
67
- x: number
68
- y: number
69
- width: number
70
- height: number
71
- children: PositionedArchitectureGroup[]
72
- }
73
-
74
- export interface PositionedArchitectureService {
75
- id: string
76
- label: string
77
- icon?: string
78
- parentId?: string
79
- x: number
80
- y: number
81
- width: number
82
- height: number
83
- }
84
-
85
- export interface PositionedArchitectureJunction {
86
- id: string
87
- parentId?: string
88
- x: number
89
- y: number
90
- width: number
91
- height: number
92
- }
93
-
94
- export interface PositionedArchitectureEdge {
95
- source: ArchitectureEndpoint
96
- target: ArchitectureEndpoint
97
- label?: string
98
- hasArrowStart: boolean
99
- hasArrowEnd: boolean
100
- points: Point[]
101
- labelPosition?: Point
102
- }
103
-
104
- export interface PositionedArchitectureDiagram extends PositionedDiagram {
105
- width: number
106
- height: number
107
- groups: PositionedArchitectureGroup[]
108
- services: PositionedArchitectureService[]
109
- junctions: PositionedArchitectureJunction[]
110
- edges: PositionedArchitectureEdge[]
111
- accessibilityTitle?: string
112
- accessibilityDescription?: string
113
- }
package/src/ascii/ansi.ts DELETED
@@ -1,423 +0,0 @@
1
- // ============================================================================
2
- // ASCII renderer — color utilities
3
- //
4
- // Provides color output for themed ASCII diagrams.
5
- // Supports ANSI terminal modes (16/256/truecolor) and HTML <span> tags
6
- // for browser rendering.
7
- // ============================================================================
8
-
9
- import { parseHex, mixHex, luma255 } from '../shared/color-math.ts'
10
- import type { CharRole, AsciiTheme, ColorMode } from './types.ts'
11
- import type { DiagramColors } from '../theme.ts'
12
- import { MIX } from '../theme.ts'
13
-
14
- declare const document: unknown
15
-
16
- // ============================================================================
17
- // Default theme — matches SVG theme colors for consistency
18
- // ============================================================================
19
-
20
- /**
21
- * Default ASCII theme derived from the SVG renderer's color palette.
22
- * Uses the same mixing ratios to maintain visual consistency.
23
- */
24
- export const DEFAULT_ASCII_THEME: AsciiTheme = {
25
- fg: '#27272a', // zinc-800 — primary text
26
- border: '#a1a1aa', // zinc-400 — node borders (12% mix)
27
- line: '#71717a', // zinc-500 — edge lines (35% mix)
28
- arrow: '#52525b', // zinc-600 — arrowheads (60% mix)
29
- corner: '#71717a', // same as line
30
- junction: '#a1a1aa', // same as border
31
- }
32
-
33
- // ============================================================================
34
- // DiagramColors → AsciiTheme bridge
35
- //
36
- // Converts SVG DiagramColors into an AsciiTheme using the same MIX ratios
37
- // that the SVG renderer uses via CSS color-mix(). This ensures visual
38
- // consistency between SVG and ASCII output for any theme.
39
- // ============================================================================
40
-
41
- /** Mix fg into bg at a given percentage (replicates CSS color-mix(in srgb)). */
42
- const mixColors = mixHex
43
-
44
- /**
45
- * Derive an AsciiTheme from SVG DiagramColors using the same mixing ratios.
46
- * Honors optional enrichment colors (line, accent, border) when present,
47
- * otherwise falls back to color-mix derivation — matching SVG behavior.
48
- */
49
- export function diagramColorsToAsciiTheme(colors: DiagramColors): AsciiTheme {
50
- const line = colors.line ?? mixColors(colors.fg, colors.bg, MIX.line)
51
- const border = colors.border ?? mixColors(colors.fg, colors.bg, MIX.nodeStroke)
52
- return {
53
- fg: colors.fg,
54
- border,
55
- line,
56
- arrow: colors.accent ?? mixColors(colors.fg, colors.bg, MIX.arrow),
57
- accent: colors.accent,
58
- bg: colors.bg,
59
- corner: line,
60
- junction: border,
61
- }
62
- }
63
-
64
- // ============================================================================
65
- // Color mode detection
66
- // ============================================================================
67
-
68
- /**
69
- * Detect the best color mode for the current environment.
70
- *
71
- * Terminal detection order:
72
- * 1. COLORTERM=truecolor or COLORTERM=24bit → truecolor
73
- * 2. TERM contains "256color" → ansi256
74
- * 3. TERM is set and not "dumb" → ansi16
75
- *
76
- * Browser: returns 'html' (uses <span> tags with inline styles).
77
- * Unknown/piped: returns 'none'.
78
- */
79
- export function detectColorMode(): ColorMode {
80
- // Check if we're in a Node.js-like environment with process object
81
- // Use globalThis to safely check for process without TypeScript errors
82
- const proc = (globalThis as { process?: { stdout?: { isTTY?: boolean }, env?: Record<string, string | undefined> } }).process
83
-
84
- if (proc) {
85
- // Check if stdout is a TTY (not piped/redirected)
86
- if (!proc.stdout?.isTTY) {
87
- return 'none'
88
- }
89
-
90
- const colorTerm = proc.env?.COLORTERM?.toLowerCase() ?? ''
91
- const term = proc.env?.TERM?.toLowerCase() ?? ''
92
-
93
- // True color support
94
- if (colorTerm === 'truecolor' || colorTerm === '24bit') {
95
- return 'truecolor'
96
- }
97
-
98
- // 256 color support
99
- if (term.includes('256color') || term.includes('256')) {
100
- return 'ansi256'
101
- }
102
-
103
- // Basic color support
104
- if (term && term !== 'dumb') {
105
- return 'ansi16'
106
- }
107
-
108
- return 'none'
109
- }
110
-
111
- // No process object → browser environment → use HTML color output
112
- if (typeof document !== 'undefined') {
113
- return 'html'
114
- }
115
-
116
- return 'none'
117
- }
118
-
119
- // ============================================================================
120
- // Hex color parsing
121
- // ============================================================================
122
-
123
- // ============================================================================
124
- // ANSI escape code generation
125
- // ============================================================================
126
-
127
- /** ANSI escape sequence prefix */
128
- const ESC = '\x1b['
129
- /** Reset all attributes */
130
- const RESET = `${ESC}0m`
131
-
132
- /**
133
- * Generate ANSI foreground color escape sequence for 24-bit true color.
134
- * Format: ESC[38;2;R;G;Bm
135
- */
136
- function truecolorFg(hex: string): string {
137
- const [r, g, b] = parseHex(hex)
138
- return `${ESC}38;2;${r};${g};${b}m`
139
- }
140
-
141
- /**
142
- * Find the closest 256-color palette index for an RGB color.
143
- * The 256-color palette has:
144
- * - 0-15: Standard colors (duplicates of 16-color)
145
- * - 16-231: 6x6x6 color cube (216 colors)
146
- * - 232-255: Grayscale ramp (24 shades)
147
- */
148
- function rgbTo256(r: number, g: number, b: number): number {
149
- // Check if it's close to grayscale
150
- const avg = (r + g + b) / 3
151
- const maxDiff = Math.max(Math.abs(r - avg), Math.abs(g - avg), Math.abs(b - avg))
152
-
153
- if (maxDiff < 10) {
154
- // Use grayscale ramp (232-255)
155
- // Each step is ~10.625 (256/24)
156
- const gray = Math.round((avg / 255) * 23)
157
- return 232 + Math.min(23, Math.max(0, gray))
158
- }
159
-
160
- // Use 6x6x6 color cube (16-231)
161
- // Each channel maps to 0-5: 0, 95, 135, 175, 215, 255
162
- const toIndex = (v: number): number => {
163
- if (v < 48) return 0
164
- if (v < 115) return 1
165
- return Math.min(5, Math.floor((v - 35) / 40))
166
- }
167
-
168
- const ri = toIndex(r)
169
- const gi = toIndex(g)
170
- const bi = toIndex(b)
171
-
172
- return 16 + (36 * ri) + (6 * gi) + bi
173
- }
174
-
175
- /**
176
- * Generate ANSI foreground color escape sequence for 256-color mode.
177
- * Format: ESC[38;5;Nm
178
- */
179
- function ansi256Fg(hex: string): string {
180
- const [r, g, b] = parseHex(hex)
181
- const index = rgbTo256(r, g, b)
182
- return `${ESC}38;5;${index}m`
183
- }
184
-
185
- /**
186
- * Map an RGB color to the closest 16-color ANSI code.
187
- * Returns the foreground color escape sequence.
188
- *
189
- * Standard 16 colors:
190
- * 0=black, 1=red, 2=green, 3=yellow, 4=blue, 5=magenta, 6=cyan, 7=white
191
- * 8-15 = bright versions
192
- */
193
- function ansi16Fg(hex: string): string {
194
- const [r, g, b] = parseHex(hex)
195
- const luma = luma255(r, g, b)
196
-
197
- // Determine brightness (use bright colors for better visibility)
198
- const bright = luma > 100 ? 0 : 60 // 60 = bright variant offset
199
-
200
- // Determine base color based on dominant channel
201
- let code: number
202
- if (r > 180 && g < 100 && b < 100) code = 31 // red
203
- else if (g > 180 && r < 100 && b < 100) code = 32 // green
204
- else if (r > 150 && g > 150 && b < 100) code = 33 // yellow
205
- else if (b > 180 && r < 100 && g < 100) code = 34 // blue
206
- else if (r > 150 && b > 150 && g < 100) code = 35 // magenta
207
- else if (g > 150 && b > 150 && r < 100) code = 36 // cyan
208
- else if (luma > 200) code = 37 // white
209
- else if (luma < 50) code = 30 // black
210
- else code = 37 // default to white for grays
211
-
212
- return `${ESC}${code + bright}m`
213
- }
214
-
215
- // ============================================================================
216
- // HTML color output (for browser rendering)
217
- // ============================================================================
218
-
219
- /** Escape characters that would break HTML output. */
220
- function escapeHtml(text: string): string {
221
- return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
222
- }
223
-
224
- /** Wrap text in a <span> with an inline color style. */
225
- function htmlSpan(hex: string, text: string): string {
226
- return `<span style="color:${hex}">${escapeHtml(text)}</span>`
227
- }
228
-
229
- // ============================================================================
230
- // Role → color mapping
231
- // ============================================================================
232
-
233
- /**
234
- * Get the color for a character role from the theme.
235
- */
236
- function getRoleColor(role: CharRole, theme: AsciiTheme): string {
237
- switch (role) {
238
- case 'text': return theme.fg
239
- case 'border': return theme.border
240
- case 'line': return theme.line
241
- case 'arrow': return theme.arrow
242
- case 'corner': return theme.corner ?? theme.line
243
- case 'junction': return theme.junction ?? theme.border
244
- default: return theme.fg
245
- }
246
- }
247
-
248
- /**
249
- * Generate the ANSI escape sequence for a role color.
250
- */
251
- export function getAnsiColor(role: CharRole, theme: AsciiTheme, mode: ColorMode): string {
252
- if (mode === 'none') return ''
253
-
254
- const hex = getRoleColor(role, theme)
255
-
256
- switch (mode) {
257
- case 'truecolor': return truecolorFg(hex)
258
- case 'ansi256': return ansi256Fg(hex)
259
- case 'ansi16': return ansi16Fg(hex)
260
- default: return ''
261
- }
262
- }
263
-
264
- /**
265
- * Get the ANSI reset sequence.
266
- */
267
- export function getAnsiReset(mode: ColorMode): string {
268
- return mode === 'none' ? '' : RESET
269
- }
270
-
271
- /**
272
- * Wrap a character with ANSI color codes based on its role.
273
- */
274
- export function colorizeChar(
275
- char: string,
276
- role: CharRole | null,
277
- theme: AsciiTheme,
278
- mode: ColorMode,
279
- ): string {
280
- if (mode === 'none' || role === null || char === ' ') {
281
- return char
282
- }
283
-
284
- const colorCode = getAnsiColor(role, theme, mode)
285
- return `${colorCode}${char}${RESET}`
286
- }
287
-
288
- /**
289
- * Colorize an entire line efficiently by grouping consecutive same-role characters.
290
- * This reduces the number of escape sequences (ANSI) or span tags (HTML) in the output.
291
- */
292
- export function colorizeLine(
293
- chars: string[],
294
- roles: (CharRole | null)[],
295
- theme: AsciiTheme,
296
- mode: ColorMode,
297
- ): string {
298
- if (mode === 'none') {
299
- return chars.join('')
300
- }
301
-
302
- if (mode === 'html') {
303
- return colorizeLineHtml(chars, roles, theme)
304
- }
305
-
306
- let result = ''
307
- let currentRole: CharRole | null = null
308
- let buffer = ''
309
-
310
- for (let i = 0; i < chars.length; i++) {
311
- const char = chars[i]!
312
- const role = roles[i] ?? null
313
-
314
- // Whitespace doesn't need coloring
315
- if (char === ' ') {
316
- // Flush any buffered characters (with or without color)
317
- if (buffer.length > 0) {
318
- if (currentRole !== null) {
319
- result += getAnsiColor(currentRole, theme, mode) + buffer + RESET
320
- } else {
321
- result += buffer
322
- }
323
- buffer = ''
324
- currentRole = null
325
- }
326
- result += char
327
- continue
328
- }
329
-
330
- // Same role as previous — accumulate
331
- if (role === currentRole) {
332
- buffer += char
333
- continue
334
- }
335
-
336
- // Role changed — flush buffer (with or without color) and start new
337
- if (buffer.length > 0) {
338
- if (currentRole !== null) {
339
- result += getAnsiColor(currentRole, theme, mode) + buffer + RESET
340
- } else {
341
- result += buffer
342
- }
343
- }
344
- buffer = char
345
- currentRole = role
346
- }
347
-
348
- // Flush remaining buffer
349
- if (buffer.length > 0 && currentRole !== null) {
350
- result += getAnsiColor(currentRole, theme, mode) + buffer + RESET
351
- } else if (buffer.length > 0) {
352
- result += buffer
353
- }
354
-
355
- return result
356
- }
357
-
358
- /**
359
- * HTML-specific line colorization.
360
- * Groups consecutive same-role characters into <span> tags with inline color styles.
361
- * Whitespace is emitted bare (no wrapping) to keep output compact.
362
- */
363
- function colorizeLineHtml(
364
- chars: string[],
365
- roles: (CharRole | null)[],
366
- theme: AsciiTheme,
367
- ): string {
368
- let result = ''
369
- let currentRole: CharRole | null = null
370
- let buffer = ''
371
-
372
- const flush = () => {
373
- if (buffer.length === 0) return
374
- if (currentRole !== null) {
375
- result += htmlSpan(getRoleColor(currentRole, theme), buffer)
376
- } else {
377
- result += escapeHtml(buffer)
378
- }
379
- buffer = ''
380
- currentRole = null
381
- }
382
-
383
- for (let i = 0; i < chars.length; i++) {
384
- const char = chars[i]!
385
- const role = roles[i] ?? null
386
-
387
- if (char === ' ') {
388
- flush()
389
- result += ' '
390
- continue
391
- }
392
-
393
- if (role === currentRole) {
394
- buffer += char
395
- continue
396
- }
397
-
398
- flush()
399
- buffer = char
400
- currentRole = role
401
- }
402
-
403
- flush()
404
- return result
405
- }
406
-
407
- /**
408
- * Colorize a text string with a direct hex color.
409
- * Used by renderers that need per-cell color control (e.g. multi-series xychart).
410
- * Handles all output modes: ANSI (16/256/truecolor) and HTML.
411
- */
412
- export function colorizeText(text: string, hex: string, mode: ColorMode): string {
413
- if (mode === 'none' || text.length === 0) return text
414
- if (mode === 'html') return htmlSpan(hex, text)
415
- let code: string
416
- switch (mode) {
417
- case 'truecolor': code = truecolorFg(hex); break
418
- case 'ansi256': code = ansi256Fg(hex); break
419
- case 'ansi16': code = ansi16Fg(hex); break
420
- default: return text
421
- }
422
- return `${code}${text}${RESET}`
423
- }