@inflexa-ai/harness 0.42.2 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/sandbox/shared.d.ts +1 -6
  3. package/dist/agents/sandbox/shared.js +0 -15
  4. package/dist/app/chat-turn.js +13 -1
  5. package/dist/config/environment-stores.d.ts +4 -2
  6. package/dist/contracts/chat-events.d.ts +9 -1
  7. package/dist/contracts/chat-frame.d.ts +3 -3
  8. package/dist/contracts/chat-frame.js +8 -3
  9. package/dist/contracts/chat-parts.d.ts +4 -1
  10. package/dist/contracts/data-profile.d.ts +4 -6
  11. package/dist/contracts/index.d.ts +1 -1
  12. package/dist/contracts/report-blocks.d.ts +1364 -75
  13. package/dist/contracts/report-blocks.js +221 -29
  14. package/dist/contracts/report-reference.js +1 -1
  15. package/dist/contracts/schemas/chat-events.d.ts +13 -0
  16. package/dist/contracts/schemas/chat-events.js +5 -0
  17. package/dist/contracts/schemas/chat-parts.d.ts +2 -2
  18. package/dist/contracts/schemas/index.d.ts +1 -1
  19. package/dist/contracts/schemas/index.js +1 -1
  20. package/dist/execution/input-signature.d.ts +7 -13
  21. package/dist/execution/input-signature.js +0 -0
  22. package/dist/execution/run-canceler.d.ts +3 -2
  23. package/dist/execution/run-canceler.js +3 -2
  24. package/dist/execution/run-event-stream.d.ts +16 -2
  25. package/dist/execution/run-event-stream.js +54 -3
  26. package/dist/index.d.ts +1 -8
  27. package/dist/index.js +5 -16
  28. package/dist/input-scan/enrich.d.ts +0 -2
  29. package/dist/input-scan/enrich.js +0 -1
  30. package/dist/lib/metrics.js +6 -7
  31. package/dist/lib/otel-spans.d.ts +4 -9
  32. package/dist/lib/otel-spans.js +3 -8
  33. package/dist/loop/run-agent.d.ts +4 -2
  34. package/dist/loop/run-agent.js +38 -23
  35. package/dist/memory/thread-history.d.ts +1 -1
  36. package/dist/prompts/report-session.d.ts +1 -1
  37. package/dist/prompts/report-session.js +17 -0
  38. package/dist/provenance/exec-frame.d.ts +1 -1
  39. package/dist/report-model/authoring-grammar.d.ts +416 -17
  40. package/dist/report-model/authoring-grammar.js +25 -4
  41. package/dist/report-model/block-walk.d.ts +20 -4
  42. package/dist/report-model/block-walk.js +64 -7
  43. package/dist/report-model/draft-finish.d.ts +6 -2
  44. package/dist/report-model/draft-finish.js +6 -1
  45. package/dist/report-model/production-resolver.d.ts +8 -0
  46. package/dist/report-model/production-resolver.js +1 -1
  47. package/dist/report-model/validate.d.ts +20 -10
  48. package/dist/report-model/validate.js +29 -13
  49. package/dist/report-render/chart-export.d.ts +52 -0
  50. package/dist/report-render/chart-export.js +192 -0
  51. package/dist/report-render/chart-presets.d.ts +46 -47
  52. package/dist/report-render/chart-presets.js +31 -101
  53. package/dist/report-render/chart-renderers.d.ts +163 -0
  54. package/dist/report-render/chart-renderers.js +1055 -0
  55. package/dist/report-render/chart-toolbox.d.ts +124 -0
  56. package/dist/report-render/chart-toolbox.js +595 -0
  57. package/dist/report-render/chart.d.ts +60 -27
  58. package/dist/report-render/chart.js +2323 -524
  59. package/dist/report-render/design.d.ts +476 -16
  60. package/dist/report-render/design.js +390 -56
  61. package/dist/report-render/figures/common.d.ts +321 -0
  62. package/dist/report-render/figures/common.js +759 -0
  63. package/dist/report-render/figures/dendrogram.d.ts +36 -0
  64. package/dist/report-render/figures/dendrogram.js +130 -0
  65. package/dist/report-render/figures/dense.d.ts +111 -0
  66. package/dist/report-render/figures/dense.js +204 -0
  67. package/dist/report-render/figures/dotplot.d.ts +28 -0
  68. package/dist/report-render/figures/dotplot.js +234 -0
  69. package/dist/report-render/figures/embedding.d.ts +43 -0
  70. package/dist/report-render/figures/embedding.js +360 -0
  71. package/dist/report-render/figures/equal-units.d.ts +101 -0
  72. package/dist/report-render/figures/equal-units.js +215 -0
  73. package/dist/report-render/figures/forest.d.ts +20 -0
  74. package/dist/report-render/figures/forest.js +398 -0
  75. package/dist/report-render/figures/gsea.d.ts +30 -0
  76. package/dist/report-render/figures/gsea.js +391 -0
  77. package/dist/report-render/figures/heatmap.d.ts +40 -0
  78. package/dist/report-render/figures/heatmap.js +395 -0
  79. package/dist/report-render/figures/index.d.ts +135 -0
  80. package/dist/report-render/figures/index.js +100 -0
  81. package/dist/report-render/figures/km.d.ts +16 -0
  82. package/dist/report-render/figures/km.js +406 -0
  83. package/dist/report-render/figures/label-room.d.ts +130 -0
  84. package/dist/report-render/figures/label-room.js +341 -0
  85. package/dist/report-render/figures/locuszoom.d.ts +50 -0
  86. package/dist/report-render/figures/locuszoom.js +675 -0
  87. package/dist/report-render/figures/lollipop.d.ts +16 -0
  88. package/dist/report-render/figures/lollipop.js +247 -0
  89. package/dist/report-render/figures/ma.d.ts +20 -0
  90. package/dist/report-render/figures/ma.js +114 -0
  91. package/dist/report-render/figures/manhattan.d.ts +60 -0
  92. package/dist/report-render/figures/manhattan.js +343 -0
  93. package/dist/report-render/figures/oncoprint.d.ts +41 -0
  94. package/dist/report-render/figures/oncoprint.js +420 -0
  95. package/dist/report-render/figures/pca.d.ts +37 -0
  96. package/dist/report-render/figures/pca.js +241 -0
  97. package/dist/report-render/figures/qq.d.ts +30 -0
  98. package/dist/report-render/figures/qq.js +182 -0
  99. package/dist/report-render/figures/roc.d.ts +17 -0
  100. package/dist/report-render/figures/roc.js +116 -0
  101. package/dist/report-render/figures/sankey.d.ts +48 -0
  102. package/dist/report-render/figures/sankey.js +353 -0
  103. package/dist/report-render/figures/upset.d.ts +60 -0
  104. package/dist/report-render/figures/upset.js +316 -0
  105. package/dist/report-render/figures/volcano.d.ts +25 -0
  106. package/dist/report-render/figures/volcano.js +166 -0
  107. package/dist/report-render/hybrid-svg.d.ts +75 -0
  108. package/dist/report-render/hybrid-svg.js +504 -0
  109. package/dist/report-render/number-format.d.ts +19 -0
  110. package/dist/report-render/number-format.js +25 -1
  111. package/dist/report-render/page.d.ts +41 -4
  112. package/dist/report-render/page.js +247 -12
  113. package/dist/report-render/render.d.ts +13 -4
  114. package/dist/report-render/render.js +37 -6
  115. package/dist/report-render/types.d.ts +23 -2
  116. package/dist/report-render/value-bridge.d.ts +38 -3
  117. package/dist/report-render/value-bridge.js +137 -6
  118. package/dist/report-render/views/chart-view.d.ts +42 -6
  119. package/dist/report-render/views/chart-view.js +70 -9
  120. package/dist/report-render/views/page-view.js +9 -10
  121. package/dist/runtime/assemble.js +2 -2
  122. package/dist/sandbox/client.d.ts +23 -32
  123. package/dist/sandbox/client.js +3 -11
  124. package/dist/sandbox/create-sandbox.d.ts +9 -24
  125. package/dist/sandbox/create-sandbox.js +15 -30
  126. package/dist/sandbox/docker-client.d.ts +12 -22
  127. package/dist/sandbox/docker-client.js +29 -43
  128. package/dist/sandbox/exec.d.ts +58 -0
  129. package/dist/sandbox/exec.js +197 -0
  130. package/dist/sandbox/identity.d.ts +5 -5
  131. package/dist/sandbox/identity.js +7 -10
  132. package/dist/sandbox/k8s-client.d.ts +4 -10
  133. package/dist/sandbox/k8s-client.js +5 -12
  134. package/dist/sandbox/liveness.d.ts +5 -12
  135. package/dist/sandbox/liveness.js +5 -12
  136. package/dist/sandbox/notification-sweep.d.ts +4 -7
  137. package/dist/sandbox/notification-sweep.js +4 -7
  138. package/dist/sandbox/reaper.d.ts +3 -3
  139. package/dist/sandbox/reaper.js +3 -3
  140. package/dist/sandbox/sandbox-error.d.ts +10 -11
  141. package/dist/sandbox/sandbox-error.js +10 -11
  142. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  143. package/dist/sandbox/sandbox-step-translate.js +1 -1
  144. package/dist/sandbox/types.d.ts +31 -99
  145. package/dist/sandbox/types.js +17 -84
  146. package/dist/state/active-sandboxes.d.ts +7 -32
  147. package/dist/state/active-sandboxes.js +11 -46
  148. package/dist/state/index.d.ts +1 -2
  149. package/dist/state/index.js +1 -1
  150. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.d.ts +7 -0
  151. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.js +12 -0
  152. package/dist/state/migrations/index.js +2 -0
  153. package/dist/state/schema.d.ts +1 -5
  154. package/dist/state/schema.js +1 -6
  155. package/dist/state/step-executions.js +1 -2
  156. package/dist/tasks/data-profile.js +7 -20
  157. package/dist/tasks/derive-table-exec.d.ts +4 -14
  158. package/dist/tasks/derive-table-exec.js +9 -24
  159. package/dist/tasks/extract-values.d.ts +2 -2
  160. package/dist/tasks/extract-values.js +4 -7
  161. package/dist/tools/define-tool.d.ts +56 -13
  162. package/dist/tools/define-tool.js +28 -1
  163. package/dist/tools/execute-analysis.js +3 -3
  164. package/dist/tools/report-session/derive-table.d.ts +8 -9
  165. package/dist/tools/report-session/derive-table.js +3 -4
  166. package/dist/tools/report-session/preview-report.js +4 -49
  167. package/dist/tools/sandbox/list-available-packages.d.ts +1 -1
  168. package/dist/tools/sandbox/list-available-packages.js +5 -4
  169. package/dist/tools/workspace/edit-file.d.ts +5 -4
  170. package/dist/tools/workspace/edit-file.js +10 -13
  171. package/dist/tools/workspace/execute-command.d.ts +27 -42
  172. package/dist/tools/workspace/execute-command.js +42 -38
  173. package/dist/tools/workspace/index.d.ts +5 -6
  174. package/dist/tools/workspace/index.js +5 -6
  175. package/dist/tools/workspace/mutator.d.ts +43 -8
  176. package/dist/tools/workspace/mutator.js +45 -34
  177. package/dist/tools/workspace/run-exec.d.ts +3 -12
  178. package/dist/tools/workspace/run-exec.js +7 -24
  179. package/dist/tools/workspace/scan-inputs.d.ts +0 -3
  180. package/dist/tools/workspace/scan-inputs.js +0 -1
  181. package/dist/tools/workspace/write-file.d.ts +12 -3
  182. package/dist/tools/workspace/write-file.js +17 -13
  183. package/dist/workflows/sandbox-step.d.ts +7 -11
  184. package/dist/workflows/sandbox-step.js +24 -27
  185. package/package.json +3 -1
  186. package/dist/sandbox/await-exec.d.ts +0 -143
  187. package/dist/sandbox/await-exec.js +0 -417
  188. package/dist/sandbox/deliver-exec-event.d.ts +0 -25
  189. package/dist/sandbox/deliver-exec-event.js +0 -29
  190. package/dist/sandbox/digest.d.ts +0 -14
  191. package/dist/sandbox/digest.js +0 -17
  192. package/dist/sandbox/exec-id.d.ts +0 -12
  193. package/dist/sandbox/exec-id.js +0 -20
  194. package/dist/sandbox/hmac.d.ts +0 -62
  195. package/dist/sandbox/hmac.js +0 -72
  196. package/dist/sandbox/submit-exec.d.ts +0 -38
  197. package/dist/sandbox/submit-exec.js +0 -80
  198. package/dist/sandbox/watchdog.d.ts +0 -71
  199. package/dist/sandbox/watchdog.js +0 -161
@@ -78,6 +78,8 @@ const TOKEN = {
78
78
  fontSans: `"Space Grotesk Variable", system-ui, sans-serif`,
79
79
  fontMono: `"IBM Plex Mono", ui-monospace, monospace`,
80
80
  };
81
+ /** The height of the chart body on the page, in pixels, for a chart that states no height of its own. */
82
+ export const CHART_BODY_PX = 400;
81
83
  /** The style rules of the page. The renderer inlines them in one `<style>` block. */
82
84
  export const DESIGN_CSS = `${FONT_FACES}
83
85
 
@@ -831,10 +833,146 @@ a.report-citation-source:hover {
831
833
  .report-chart-card {
832
834
  padding: 16px;
833
835
  }
834
- /* The chart runtime measures the container. A container with no height shows no chart. */
836
+ /* The chart runtime measures the container. A container with no height shows no chart. A chart that needs a
837
+ taller body, or a narrower one, states its own box on the element. */
835
838
  .chart-container {
836
839
  width: 100%;
837
- height: 400px;
840
+ height: ${CHART_BODY_PX}px;
841
+ }
842
+ /* The download control of the title line. The runtime draws the toolbox icon on the canvas and binds a mouse
843
+ click alone, thus this control opens the same menu for the keyboard. It reads as a quiet label of the line. */
844
+ .report-chart-download {
845
+ float: right;
846
+ padding: 0 2px;
847
+ font: inherit;
848
+ font-size: 11px;
849
+ letter-spacing: 0.08em;
850
+ text-transform: uppercase;
851
+ color: var(--color-text-muted);
852
+ background: transparent;
853
+ border: 0;
854
+ cursor: pointer;
855
+ }
856
+ .report-chart-download:hover,
857
+ .report-chart-download[aria-expanded="true"] {
858
+ color: var(--color-primary-700);
859
+ }
860
+ .report-chart-download:focus-visible {
861
+ outline: 2px solid var(--color-primary-500);
862
+ outline-offset: 2px;
863
+ }
864
+ /* The download menu of a chart. The download control of the toolbox opens it under the control, and the page
865
+ script places it against the card. It takes the square corners and the mono labels of the card title. A menu
866
+ stands closed until the page script marks it open. */
867
+ .report-chart-menu {
868
+ position: absolute;
869
+ z-index: 20;
870
+ display: none;
871
+ flex-direction: column;
872
+ min-width: max-content;
873
+ padding: 4px 0;
874
+ background: var(--color-card);
875
+ border: 1px solid var(--color-border);
876
+ box-shadow: 0 12px 32px -12px rgba(15, 23, 42, 0.18);
877
+ }
878
+ .report-chart-menu-open {
879
+ display: flex;
880
+ }
881
+ /* A link and a control of the menu read as one kind of entry. */
882
+ .report-chart-menu-item {
883
+ display: block;
884
+ padding: 8px 16px;
885
+ font-family: var(--font-mono);
886
+ font-size: 11px;
887
+ font-weight: 600;
888
+ letter-spacing: 0.08em;
889
+ text-align: left;
890
+ text-transform: uppercase;
891
+ white-space: nowrap;
892
+ color: var(--color-text-strong);
893
+ text-decoration: none;
894
+ background: transparent;
895
+ border: 0;
896
+ cursor: pointer;
897
+ }
898
+ .report-chart-menu-item:hover,
899
+ .report-chart-menu-item:focus {
900
+ color: var(--color-primary-700);
901
+ background: var(--color-primary-50);
902
+ outline: none;
903
+ }
904
+ .report-chart-menu-item:focus-visible {
905
+ box-shadow: inset 2px 0 0 var(--color-primary-500);
906
+ }
907
+ /* The rule between the SVG entries and the PNG entries. */
908
+ .report-chart-menu-rule {
909
+ height: 1px;
910
+ margin: 4px 0;
911
+ background: var(--color-border-subtle);
912
+ }
913
+ /* The note of a chart past the export bound that holds no point layer. It stands where the SVG entries stand. */
914
+ .report-chart-menu-note {
915
+ padding: 8px 16px;
916
+ font-family: var(--font-mono);
917
+ font-size: 11px;
918
+ white-space: normal;
919
+ max-width: 16rem;
920
+ color: var(--color-text-secondary);
921
+ }
922
+ /* The note that the menu of a dense chart shows when the page cannot build its SVG file. The page shows it. */
923
+ .report-chart-menu-fault {
924
+ display: none;
925
+ }
926
+ .report-chart-menu-fault.report-chart-menu-fault-shown {
927
+ display: block;
928
+ }
929
+ /* The data view of a chart: the plotted rows as a plain table. The runtime frames the view over the chart body,
930
+ and the frame scrolls a long table. */
931
+ .report-data-view {
932
+ padding: 0 20px;
933
+ font-family: var(--font-mono);
934
+ font-size: 11px;
935
+ color: var(--color-text-strong);
936
+ }
937
+ .report-data-view table {
938
+ width: 100%;
939
+ border-collapse: collapse;
940
+ }
941
+ .report-data-view th {
942
+ position: sticky;
943
+ top: 0;
944
+ padding: 6px 8px;
945
+ font-weight: 600;
946
+ letter-spacing: 0.08em;
947
+ text-align: left;
948
+ text-transform: uppercase;
949
+ color: var(--color-text-secondary);
950
+ background: var(--color-bg-alt);
951
+ border-bottom: 1px solid var(--color-border);
952
+ }
953
+ .report-data-view td {
954
+ padding: 4px 8px;
955
+ border-bottom: 1px solid var(--color-border-subtle);
956
+ }
957
+ .report-data-view-note {
958
+ margin: 0 0 8px;
959
+ color: var(--color-text-secondary);
960
+ }
961
+ /* The chart runtime frames the view with a heading and a close control of its own, and it styles the control
962
+ inline with round corners. The frame takes the mono title and the square corners of the card. */
963
+ .chart-container div:has(> div > .report-data-view) > h4 {
964
+ font-family: var(--font-mono);
965
+ font-size: 12px;
966
+ font-weight: 600;
967
+ letter-spacing: 0.1em;
968
+ text-transform: uppercase;
969
+ color: var(--color-primary-500) !important;
970
+ }
971
+ .chart-container div:has(> div > .report-data-view) > div:last-child > div {
972
+ font-family: var(--font-mono);
973
+ letter-spacing: 0.08em;
974
+ text-transform: uppercase;
975
+ border-radius: 0 !important;
838
976
  }
839
977
 
840
978
  /* ── References appendix ──────────────────────────────── */
@@ -1052,6 +1190,14 @@ a.report-citation-source:hover {
1052
1190
  .report-lineage-popover {
1053
1191
  display: none;
1054
1192
  }
1193
+ /* Each export draws a file on the screen, and paper downloads nothing. The page script hides the toolbox of
1194
+ each chart before the print, because the chart runtime draws it inside the chart body. */
1195
+ .report-chart-menu-open {
1196
+ display: none;
1197
+ }
1198
+ .report-chart-download {
1199
+ display: none;
1200
+ }
1055
1201
  /* The printer gives the page margin. Thus the screen padding of the container drops out. */
1056
1202
  body:has(#report-sidebar) {
1057
1203
  padding-left: 0;
@@ -1154,6 +1300,173 @@ export const GRID_THEME_PARAMS = {
1154
1300
  * reads it. One source prevents a silent mismatch between the two sites.
1155
1301
  */
1156
1302
  export const ECHARTS_THEME_NAME = "inflexa";
1303
+ /**
1304
+ * The font stack of the chart text: the journal sans stack. A figure keeps its own typography on the page
1305
+ * and in the paper, thus the chart text never reads the page fonts.
1306
+ *
1307
+ * No family name takes quotes. The server render of the chart runtime writes the stack into a double-quoted
1308
+ * `style` attribute with no escape, and a double quote there breaks the SVG file.
1309
+ */
1310
+ export const CHART_FONT_STACK = "Helvetica, Arial, sans-serif";
1311
+ /**
1312
+ * The text sizes of a chart, in pixels: on the page, in the SVG and the column PNG, and in the slide PNG.
1313
+ *
1314
+ * The print size is 7 points at the column width, which is the upper bound of the Nature guide (5 to 7
1315
+ * points), at 96 pixels for each inch. The slide size reads from the back of a room at the full width of a
1316
+ * slide.
1317
+ */
1318
+ export const CHART_PAGE_TEXT_PX = 12;
1319
+ export const CHART_PRINT_TEXT_PX = 9.33;
1320
+ export const CHART_SLIDE_TEXT_PX = 24;
1321
+ /** The names of the two export themes. The registration script and the export read the same names. */
1322
+ export const CHART_PRINT_THEME_NAME = `${ECHARTS_THEME_NAME}-print`;
1323
+ export const CHART_SLIDE_THEME_NAME = `${ECHARTS_THEME_NAME}-slide`;
1324
+ /** The pixel ratio of a column PNG: 300 dots for each inch, over the 96 CSS pixels of one inch. */
1325
+ const COLUMN_PIXEL_RATIO = 300 / 96;
1326
+ /**
1327
+ * The export sizes of a chart: the single journal column, the double journal column, and a 16:9 slide.
1328
+ *
1329
+ * A column states its box in millimeters and in CSS pixels at 96 pixels for each inch: 89 × 67 mm is 336 ×
1330
+ * 253 px, and 183 × 92 mm is 692 × 348 px. The column PNG draws at a pixel ratio of 3.125, which is 300 DPI,
1331
+ * thus the single column is 1050 px wide. The slide draws at 1920 × 1080 px at a ratio of one. The columns
1332
+ * read the print text size, and the slide reads the slide text size.
1333
+ */
1334
+ export const CHART_EXPORT_SIZES = {
1335
+ single: {
1336
+ theme: CHART_PRINT_THEME_NAME,
1337
+ textPx: CHART_PRINT_TEXT_PX,
1338
+ widthPx: 336,
1339
+ heightPx: 253,
1340
+ widthMm: 89,
1341
+ heightMm: 67,
1342
+ pixelRatio: COLUMN_PIXEL_RATIO,
1343
+ label: "89 mm",
1344
+ },
1345
+ double: {
1346
+ theme: CHART_PRINT_THEME_NAME,
1347
+ textPx: CHART_PRINT_TEXT_PX,
1348
+ widthPx: 692,
1349
+ heightPx: 348,
1350
+ widthMm: 183,
1351
+ heightMm: 92,
1352
+ pixelRatio: COLUMN_PIXEL_RATIO,
1353
+ label: "183 mm",
1354
+ },
1355
+ slide: { theme: CHART_SLIDE_THEME_NAME, textPx: CHART_SLIDE_TEXT_PX, widthPx: 1920, heightPx: 1080, pixelRatio: 1, label: "16:9" },
1356
+ };
1357
+ /** The height that each further row of facet panels adds to the chart body, in pixels. */
1358
+ export const FACET_ROW_PX = 360;
1359
+ /** The largest chart body, in pixels. A figure of more rows than this height holds hides a name that overlaps its neighbor. */
1360
+ export const CHART_BODY_MAX_PX = 1480;
1361
+ /**
1362
+ * The width of the chart body on a page at a window 1280 pixels wide, in pixels. A derivation that fits its
1363
+ * category labels to the page measures them against this width.
1364
+ */
1365
+ export const CHART_PAGE_WIDTH_PX = 900;
1366
+ /** The largest height of a journal figure: 170 mm, the full page depth of the Nature guide. */
1367
+ export const CHART_EXPORT_MAX_HEIGHT_MM = 170;
1368
+ /** The CSS pixels of one millimeter, at 96 pixels for each inch. */
1369
+ const PX_PER_MM = 96 / 25.4;
1370
+ /**
1371
+ * The export size of a chart whose body is taller than the default body.
1372
+ *
1373
+ * A column export keeps its width, and its height grows in the ratio of the body to the default body, thus a
1374
+ * row of the figure keeps its share of the height in the export. The height stops at the journal maximum. A
1375
+ * slide keeps its 16:9 box, and a chart of the default body keeps each size.
1376
+ */
1377
+ export function exportSizeFor(size, bodyPx) {
1378
+ if (bodyPx <= CHART_BODY_PX || size.heightMm === undefined)
1379
+ return size;
1380
+ const heightPx = Math.min(Math.floor(CHART_EXPORT_MAX_HEIGHT_MM * PX_PER_MM), Math.round((size.heightPx * bodyPx) / CHART_BODY_PX));
1381
+ return { ...size, heightPx, heightMm: Math.round(heightPx / PX_PER_MM) };
1382
+ }
1383
+ /**
1384
+ * The near-black ink of a chart: the text, the two axis lines, and the stroke of an interval.
1385
+ *
1386
+ * A journal figure draws its frame and its text in one dark ink, thus the page and the export read alike.
1387
+ */
1388
+ export const CHART_INK = "#222222";
1389
+ /**
1390
+ * The categorical palette of a chart: the Okabe-Ito set, in the order blue, vermilion, bluish green,
1391
+ * orange, reddish purple, sky blue, yellow, and black.
1392
+ *
1393
+ * The set is public and colorblind-safe: no two hues differ by a red-green difference alone. A series that
1394
+ * names no color takes the next hue of this order.
1395
+ */
1396
+ export const CHART_PALETTE = ["#0072b2", "#d55e00", "#009e73", "#e69f00", "#cc79a7", "#56b4e9", "#f0e442", "#000000"];
1397
+ /**
1398
+ * The categorical palette of a chart that draws more than eight categories: the eight hues of the Okabe-Ito
1399
+ * set in their order, then sixteen more hues. Each hue differs from its neighbors in hue or in lightness, and
1400
+ * no hue is near white. The order is fixed, thus one category count gives one set of colors on every chart.
1401
+ *
1402
+ * Past eight categories no palette stays safe for each color-vision deficiency, thus the colors carry the
1403
+ * categories and the legend names them.
1404
+ */
1405
+ export const CHART_WIDE_PALETTE = [
1406
+ ...CHART_PALETTE,
1407
+ "#875692",
1408
+ "#8db600",
1409
+ "#be0032",
1410
+ "#a1caf1",
1411
+ "#882d17",
1412
+ "#17becf",
1413
+ "#f99379",
1414
+ "#604e97",
1415
+ "#dcd300",
1416
+ "#b3446c",
1417
+ "#2b3d26",
1418
+ "#e68fac",
1419
+ "#654522",
1420
+ "#c2b280",
1421
+ "#e7298a",
1422
+ "#7fc97f",
1423
+ ];
1424
+ /**
1425
+ * The stroke of a guide line: a thin gray dash. A guide is a reference and never a plotted value, thus it
1426
+ * reads behind the data.
1427
+ */
1428
+ export const GUIDE_LINE_COLOR = "#8c8c8c";
1429
+ export const GUIDE_LINE_WIDTH_PX = 1;
1430
+ /** The one focus color of a chart. It is the first hue of the palette, thus a focus reads as the lead series. */
1431
+ export const FOCUS_CHART_COLOR = CHART_PALETTE[0];
1432
+ /**
1433
+ * The sequential ramp of a continuous color: the ten stops of viridis, dark to light. A continuous scale maps
1434
+ * the low value to `#440154` and the high value to `#fde725`.
1435
+ */
1436
+ export const SEQUENTIAL_RAMP = ["#440154", "#482777", "#3e4989", "#31688e", "#26828e", "#1f9e89", "#35b779", "#6ece58", "#b5de2b", "#fde725"];
1437
+ /**
1438
+ * The diverging ramp of a continuous color: the palette blue through a near-white to the palette vermilion.
1439
+ * The derivation centers the ramp on zero, thus the near-white stop marks no change.
1440
+ */
1441
+ export const DIVERGING_RAMP = [CHART_PALETTE[0], "#f7f7f7", CHART_PALETTE[1]];
1442
+ /** The smallest and the largest symbol of a `size` channel, in pixels. */
1443
+ export const SIZE_CHANNEL_RANGE_PX = [6, 24];
1444
+ /**
1445
+ * The band at the right edge of a chart that a continuous color scale takes, in percent of the width. The plot
1446
+ * leaves the band free, and the title of the scale in an export wraps into it.
1447
+ */
1448
+ export const COLOR_SCALE_BAND_PCT = 18;
1449
+ /**
1450
+ * The largest count of slots of one chart, where a slot is one pair of a category and a group. A stacked form,
1451
+ * a radar, a violin, and a heatmap lay out one slot for each pair, thus the bound holds their grids to a size
1452
+ * that a reader reads and that the render holds in memory.
1453
+ */
1454
+ export const CHART_SLOT_LIMIT = 100_000;
1455
+ /**
1456
+ * The largest count of bars that carry a value label, counted across the series of one chart.
1457
+ *
1458
+ * A label on each of a few bars reads as the exact value beside the bar. Past this count the labels crowd
1459
+ * each other, and the axis reads better alone.
1460
+ */
1461
+ export const BAR_VALUE_LABEL_LIMIT = 12;
1462
+ /**
1463
+ * The largest count of facet panels of one chart, and the count of panels in one row.
1464
+ *
1465
+ * A small multiple compares its panels at a glance. Past twelve panels each panel is too small to read, and
1466
+ * a derived table of fewer groups serves the reader better.
1467
+ */
1468
+ export const FACET_PANEL_LIMIT = 12;
1469
+ export const FACET_COLUMNS = 3;
1157
1470
  /**
1158
1471
  * The muted chart color, beside the palette of the theme.
1159
1472
  *
@@ -1188,59 +1501,80 @@ export const SCATTER_CROWD_OPACITY = 0.5;
1188
1501
  */
1189
1502
  export const CHART_INLINE_OPTION_BOUND = 100_000;
1190
1503
  /**
1191
- * The ECharts theme as a plain object. The renderer serializes this object and registers it, thus the theme
1192
- * never rides a JSON file and no run-time read is necessary. The palette and the axis styles mirror the
1193
- * light design tokens above.
1504
+ * The publication theme of a chart, at one text size.
1505
+ *
1506
+ * The page and the export read one theme, thus a chart on the page is the chart that the paper gets. The
1507
+ * left and the bottom axis lines are strong and dark, with ticks outside the plot. There is no grid line, no
1508
+ * frame around the legend, and no toolbox, because the chart card adds the toolbox of the page and a file carries
1509
+ * none. The text reads in the journal sans stack and in the near-black ink.
1510
+ *
1511
+ * The chart runtime reads the style of an axis by its type, thus each of the four axis types carries the same
1512
+ * style. The text size scales the text alone: the page, the print export, and the slide export each register
1513
+ * one theme.
1194
1514
  */
1195
- export const ECHARTS_THEME = {
1196
- color: ["#576dea", "#ef4444", "#22c55e", "#a78bfa", "#f59e0b", "#ec4899", "#06b6d4", "#f97316", "#8b5cf6", "#14b8a6"],
1197
- backgroundColor: "transparent",
1198
- textStyle: {
1199
- fontFamily: "'Space Grotesk Variable', system-ui, sans-serif",
1200
- fontSize: 12,
1201
- color: "#64748b",
1202
- },
1203
- title: {
1204
- show: false,
1205
- },
1206
- legend: {
1207
- bottom: 0,
1208
- textStyle: { fontSize: 11, color: "#64748b" },
1209
- itemGap: 16,
1210
- itemWidth: 12,
1211
- itemHeight: 12,
1212
- },
1213
- grid: {
1214
- left: 60,
1215
- right: 24,
1216
- top: 24,
1217
- bottom: 48,
1218
- containLabel: false,
1219
- },
1220
- tooltip: {
1221
- backgroundColor: "#ffffff",
1222
- borderColor: "#e2e8f0",
1223
- textStyle: { color: "#334155", fontSize: 12 },
1224
- extraCssText: "border-radius: 4px; box-shadow: 0 4px 12px rgba(15,23,42,0.1);",
1225
- },
1226
- toolbox: {
1227
- feature: {
1228
- saveAsImage: { title: "Save", pixelRatio: 2 },
1515
+ export function chartTheme(textPx) {
1516
+ const axis = {
1517
+ axisLine: { show: true, lineStyle: { color: CHART_INK, width: CHART_AXIS_LINE_PX } },
1518
+ axisTick: { show: true, inside: false, lineStyle: { color: CHART_INK, width: CHART_AXIS_LINE_PX } },
1519
+ axisLabel: { color: CHART_INK, fontSize: textPx },
1520
+ splitLine: { show: false },
1521
+ nameTextStyle: { color: CHART_INK, fontSize: textPx },
1522
+ };
1523
+ // A value axis draws its line at the edge of the plot, thus the left and the bottom lines frame the figure.
1524
+ // A category axis keeps its line on the zero of the value axis, thus a bar stands on a zero baseline.
1525
+ const valueAxis = { ...axis, axisLine: { ...axis.axisLine, onZero: false } };
1526
+ return {
1527
+ color: [...CHART_PALETTE],
1528
+ backgroundColor: "transparent",
1529
+ textStyle: { fontFamily: CHART_FONT_STACK, fontSize: textPx, color: CHART_INK },
1530
+ title: { show: false },
1531
+ legend: {
1532
+ bottom: 0,
1533
+ borderWidth: 0,
1534
+ textStyle: { fontFamily: CHART_FONT_STACK, fontSize: textPx, color: CHART_INK },
1535
+ itemGap: 16,
1536
+ itemWidth: textPx,
1537
+ itemHeight: textPx,
1229
1538
  },
1230
- iconStyle: { borderColor: "#94a3b8" },
1231
- right: 16,
1232
- top: 0,
1233
- },
1234
- xAxis: {
1235
- axisLine: { lineStyle: { color: "#e2e8f0" } },
1236
- axisTick: { lineStyle: { color: "#e2e8f0" } },
1237
- axisLabel: { color: "#64748b", fontSize: 11 },
1238
- splitLine: { lineStyle: { color: "#f1f5f9", type: "dashed" } },
1239
- },
1240
- yAxis: {
1241
- axisLine: { show: false },
1242
- axisTick: { show: false },
1243
- axisLabel: { color: "#64748b", fontSize: 11 },
1244
- splitLine: { lineStyle: { color: "#f1f5f9", type: "dashed" } },
1245
- },
1246
- };
1539
+ grid: { left: 60, right: 24, top: 24, bottom: 48, containLabel: false },
1540
+ tooltip: {
1541
+ backgroundColor: "#ffffff",
1542
+ borderColor: "#e2e8f0",
1543
+ textStyle: { color: "#334155", fontSize: 12 },
1544
+ extraCssText: "border-radius: 4px; box-shadow: 0 4px 12px rgba(15,23,42,0.1);",
1545
+ },
1546
+ categoryAxis: axis,
1547
+ valueAxis,
1548
+ logAxis: valueAxis,
1549
+ timeAxis: valueAxis,
1550
+ visualMap: { textStyle: { fontFamily: CHART_FONT_STACK, fontSize: textPx, color: CHART_INK } },
1551
+ radar: {
1552
+ axisName: { color: CHART_INK, fontSize: textPx },
1553
+ axisLine: { lineStyle: { color: CHART_RADAR_WEB } },
1554
+ splitLine: { lineStyle: { color: CHART_RADAR_WEB } },
1555
+ splitArea: { show: false },
1556
+ },
1557
+ };
1558
+ }
1559
+ /** The width of the two axis lines and of their ticks, in pixels. */
1560
+ const CHART_AXIS_LINE_PX = 1.5;
1561
+ /** The light web of a radar. The web is the coordinate of the radar, thus it stays and recedes. */
1562
+ const CHART_RADAR_WEB = "#d4d4d4";
1563
+ /**
1564
+ * The colors and the font of the toolbox of a page chart: a quiet icon, the primary accent on hover, and the mono
1565
+ * face of the card title for the title of an icon.
1566
+ */
1567
+ export const CHART_TOOLBOX_ICON_COLOR = TOKEN.textSecondary;
1568
+ export const CHART_TOOLBOX_ACTIVE_COLOR = TOKEN.primary500;
1569
+ export const CHART_TOOLBOX_FONT = TOKEN.fontMono;
1570
+ /** The theme that the page registers under `ECHARTS_THEME_NAME`, at the page text size. */
1571
+ export const ECHARTS_THEME = chartTheme(CHART_PAGE_TEXT_PX);
1572
+ /**
1573
+ * The registered themes: the page theme, the print theme of the SVG and the column PNG, and the slide theme.
1574
+ * The registration script writes each one, and the export reads one by its name.
1575
+ */
1576
+ export const CHART_THEMES = [
1577
+ { name: ECHARTS_THEME_NAME, textPx: CHART_PAGE_TEXT_PX },
1578
+ { name: CHART_PRINT_THEME_NAME, textPx: CHART_PRINT_TEXT_PX },
1579
+ { name: CHART_SLIDE_THEME_NAME, textPx: CHART_SLIDE_TEXT_PX },
1580
+ ];