@stephen-netu/design-system 0.2.2 → 0.5.1

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 (229) hide show
  1. package/dist/d0-data-viz/BarChart.test.js +53 -0
  2. package/dist/d0-data-viz/CheckpointBar.test.js +83 -0
  3. package/dist/d0-data-viz/CheckpointPill.svelte +1 -1
  4. package/dist/d0-data-viz/CheckpointPill.test.js +78 -0
  5. package/dist/d0-data-viz/ConnectionHealth.test.js +70 -0
  6. package/dist/d0-data-viz/MetricCard.test.js +57 -0
  7. package/dist/d0-data-viz/SparkLine.test.js +47 -0
  8. package/dist/d0-data-viz/StorageMap.test.js +63 -0
  9. package/dist/d0-data-viz/Timeline.test.js +62 -0
  10. package/dist/d0-data-viz/WorldLineTimeline.test.js +99 -0
  11. package/dist/d0-data-viz/checkpoint-types.js +1 -1
  12. package/dist/d0-data-viz/storage-map-types.d.ts.map +1 -1
  13. package/dist/d0-data-viz/storage-map-types.js +6 -3
  14. package/dist/d0-data-viz/theme-integration.js +1 -1
  15. package/dist/demos/AmbientPrimitivesDemo.svelte +103 -0
  16. package/dist/demos/AmbientPrimitivesDemo.svelte.d.ts +5 -0
  17. package/dist/demos/AmbientPrimitivesDemo.svelte.d.ts.map +1 -0
  18. package/dist/demos/NodepadBlocksShowcase.svelte +2 -1
  19. package/dist/demos/NodepadBlocksShowcase.svelte.d.ts.map +1 -1
  20. package/dist/demos/index.d.ts +1 -0
  21. package/dist/demos/index.d.ts.map +1 -1
  22. package/dist/demos/index.js +1 -0
  23. package/dist/editor/CodeEditor.svelte +83 -26
  24. package/dist/editor/CodeEditor.svelte.d.ts +0 -1
  25. package/dist/editor/CodeEditor.svelte.d.ts.map +1 -1
  26. package/dist/editor/ExternalChangeDialog.svelte +117 -0
  27. package/dist/editor/ExternalChangeDialog.svelte.d.ts +13 -0
  28. package/dist/editor/ExternalChangeDialog.svelte.d.ts.map +1 -0
  29. package/dist/editor/MarkdownEditor.svelte +104 -617
  30. package/dist/editor/MarkdownEditor.svelte.d.ts +1 -1
  31. package/dist/editor/MarkdownEditor.svelte.d.ts.map +1 -1
  32. package/dist/editor/codemirror-config.d.ts +36 -0
  33. package/dist/editor/codemirror-config.d.ts.map +1 -0
  34. package/dist/editor/codemirror-config.js +87 -0
  35. package/dist/editor/components/CorrectionTooltip.svelte +180 -159
  36. package/dist/editor/components/CorrectionTooltip.svelte.d.ts +7 -23
  37. package/dist/editor/components/CorrectionTooltip.svelte.d.ts.map +1 -1
  38. package/dist/editor/extensions/autocomplete.d.ts +2 -2
  39. package/dist/editor/extensions/autocomplete.d.ts.map +1 -1
  40. package/dist/editor/extensions/autocomplete.test.js +121 -0
  41. package/dist/editor/extensions/spellcheck.d.ts +21 -3
  42. package/dist/editor/extensions/spellcheck.d.ts.map +1 -1
  43. package/dist/editor/extensions/spellcheck.js +51 -9
  44. package/dist/editor/extensions/spellcheck.test.js +168 -0
  45. package/dist/editor/extensions/types.d.ts +2 -1
  46. package/dist/editor/extensions/types.d.ts.map +1 -1
  47. package/dist/editor/index.d.ts +2 -1
  48. package/dist/editor/index.d.ts.map +1 -1
  49. package/dist/editor/index.js +1 -0
  50. package/dist/editor/markdown-preview.d.ts +9 -0
  51. package/dist/editor/markdown-preview.d.ts.map +1 -0
  52. package/dist/editor/markdown-preview.js +19 -0
  53. package/dist/editor/markdown-preview.test.js +38 -0
  54. package/dist/editor/useCodeMirror.d.ts +23 -0
  55. package/dist/editor/useCodeMirror.d.ts.map +1 -0
  56. package/dist/editor/useCodeMirror.js +40 -0
  57. package/dist/editor/useFilePersistence.d.ts +32 -0
  58. package/dist/editor/useFilePersistence.d.ts.map +1 -0
  59. package/dist/editor/useFilePersistence.js +117 -0
  60. package/dist/fabric/ai/ChatPanel.svelte +61 -62
  61. package/dist/fabric/ai/ChatPanel.svelte.d.ts.map +1 -1
  62. package/dist/fabric/ai/ResearchPanel.svelte +31 -24
  63. package/dist/fabric/data/FileTree.svelte +195 -0
  64. package/dist/fabric/data/FileTree.svelte.d.ts +19 -0
  65. package/dist/fabric/data/FileTree.svelte.d.ts.map +1 -0
  66. package/dist/fabric/data/FileTree.test.js +127 -0
  67. package/dist/fabric/data/index.d.ts +5 -9
  68. package/dist/fabric/data/index.d.ts.map +1 -1
  69. package/dist/fabric/data/index.js +4 -1
  70. package/dist/fabric/index.d.ts +1 -0
  71. package/dist/fabric/index.d.ts.map +1 -1
  72. package/dist/fabric/index.js +2 -0
  73. package/dist/fabric/input/KeyboardShortcuts.svelte +23 -21
  74. package/dist/fabric/layout/CollapsiblePanel.svelte +8 -10
  75. package/dist/fabric/navigation/ActivityRail.svelte +3 -5
  76. package/dist/fabric/navigation/ActivityRail.svelte.d.ts.map +1 -1
  77. package/dist/g0-generative/components/Text.svelte +38 -0
  78. package/dist/g0-generative/components/Text.svelte.d.ts +9 -0
  79. package/dist/g0-generative/components/Text.svelte.d.ts.map +1 -0
  80. package/dist/g0-generative/index.d.ts +1 -0
  81. package/dist/g0-generative/index.d.ts.map +1 -1
  82. package/dist/g0-generative/index.js +1 -0
  83. package/dist/g0-generative/library/ComponentLibrary.d.ts +4 -0
  84. package/dist/g0-generative/library/ComponentLibrary.d.ts.map +1 -1
  85. package/dist/g0-generative/library/ComponentLibrary.js +10 -0
  86. package/dist/g0-generative/library/ComponentLibrary.test.js +135 -0
  87. package/dist/g0-generative/renderer/OpenUIRenderer.svelte +16 -56
  88. package/dist/g0-generative/renderer/OpenUIRenderer.svelte.d.ts.map +1 -1
  89. package/dist/g0-generative/renderer/OpenUIRenderer.test.js +143 -0
  90. package/dist/g0-geo/SovereignMap.svelte +13 -13
  91. package/dist/g0-geo/SovereignMap.svelte.d.ts.map +1 -1
  92. package/dist/index.d.ts +0 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +3 -1
  95. package/dist/l0-layout/block-writer/BlockContent.svelte +23 -22
  96. package/dist/l0-layout/block-writer/BlockContent.svelte.d.ts.map +1 -1
  97. package/dist/l0-layout/block-writer/BlockContent.test.js +47 -0
  98. package/dist/l0-layout/block-writer/markdown.js +11 -11
  99. package/dist/l0-layout/block-writer/markdown.test.js +81 -0
  100. package/dist/l0-layout/card/StackedCard.svelte +87 -0
  101. package/dist/l0-layout/card/StackedCard.svelte.d.ts +9 -0
  102. package/dist/l0-layout/card/StackedCard.svelte.d.ts.map +1 -0
  103. package/dist/l0-layout/card/StackedCard.test.js +29 -0
  104. package/dist/l0-layout/index.d.ts +1 -0
  105. package/dist/l0-layout/index.d.ts.map +1 -1
  106. package/dist/l0-layout/index.js +1 -0
  107. package/dist/l0-layout/kanban/KanbanBoard.svelte +1 -1
  108. package/dist/l0-layout/kanban/KanbanColumn.svelte +1 -1
  109. package/dist/n1-flow-canvas/FlowCanvas.svelte +50 -6
  110. package/dist/n1-flow-canvas/FlowCanvas.svelte.d.ts.map +1 -1
  111. package/dist/n1-flow-canvas/index.d.ts +2 -0
  112. package/dist/n1-flow-canvas/index.d.ts.map +1 -1
  113. package/dist/n1-flow-canvas/index.js +1 -0
  114. package/dist/n1-flow-canvas/pipeline-adapter.d.ts +37 -0
  115. package/dist/n1-flow-canvas/pipeline-adapter.d.ts.map +1 -0
  116. package/dist/n1-flow-canvas/pipeline-adapter.js +160 -0
  117. package/dist/n2-manifold-disk/ManifoldDisk.svelte +62 -35
  118. package/dist/n2-manifold-disk/ManifoldDisk.svelte.d.ts.map +1 -1
  119. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte +23 -19
  120. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte.d.ts.map +1 -1
  121. package/dist/n4-adaptive-manifold/types.d.ts +3 -0
  122. package/dist/n4-adaptive-manifold/types.d.ts.map +1 -1
  123. package/dist/p0-primitives/ThemeProvider.svelte +28 -7
  124. package/dist/p0-primitives/ThemeProvider.svelte.d.ts +5 -0
  125. package/dist/p0-primitives/ThemeProvider.svelte.d.ts.map +1 -1
  126. package/dist/p0-primitives/canvas-theme.d.ts +21 -1
  127. package/dist/p0-primitives/canvas-theme.d.ts.map +1 -1
  128. package/dist/p0-primitives/canvas-theme.js +78 -23
  129. package/dist/p0-primitives/debug.d.ts +6 -0
  130. package/dist/p0-primitives/debug.d.ts.map +1 -0
  131. package/dist/p0-primitives/debug.js +21 -0
  132. package/dist/p0-primitives/theme.d.ts.map +1 -1
  133. package/dist/p0-primitives/theme.js +11 -31
  134. package/dist/p0-primitives/tokens/ambient.css +76 -0
  135. package/dist/p0-primitives/tokens/tokens.css +124 -29
  136. package/dist/p0-primitives/utils/index.d.ts +2 -0
  137. package/dist/p0-primitives/utils/index.d.ts.map +1 -1
  138. package/dist/p0-primitives/utils/index.js +1 -0
  139. package/dist/p0-primitives/utils/reveal.d.ts +15 -0
  140. package/dist/p0-primitives/utils/reveal.d.ts.map +1 -0
  141. package/dist/p0-primitives/utils/reveal.js +29 -0
  142. package/dist/p0-primitives/utils/reveal.test.js +95 -0
  143. package/dist/s0-state/SyncStatus.svelte +1 -1
  144. package/dist/s0-state/index.d.ts +2 -1
  145. package/dist/s0-state/index.d.ts.map +1 -1
  146. package/dist/s0-state/index.js +2 -0
  147. package/dist/s0-state/modal-stack-store.svelte.d.ts +3 -3
  148. package/dist/s0-state/modal-stack-store.svelte.js +2 -2
  149. package/dist/spatial/ForceSimulation.svelte.js +1 -1
  150. package/dist/spatial/ParticleAssembleMark.svelte +285 -0
  151. package/dist/spatial/ParticleAssembleMark.svelte.d.ts +24 -0
  152. package/dist/spatial/ParticleAssembleMark.svelte.d.ts.map +1 -0
  153. package/dist/spatial/ZoneTiler.test.js +90 -0
  154. package/dist/spatial/index.js +1 -0
  155. package/dist/spatial/particle-assemble-math.d.ts +22 -0
  156. package/dist/spatial/particle-assemble-math.d.ts.map +1 -0
  157. package/dist/spatial/particle-assemble-math.js +26 -0
  158. package/dist/spatial/particle-assemble-math.test.js +56 -0
  159. package/dist/t0-transport/substrate.svelte.d.ts.map +1 -1
  160. package/dist/t0-transport/substrate.svelte.js +10 -4
  161. package/dist/u0-primitives/LockIndicator.svelte +16 -14
  162. package/dist/u0-primitives/VerticalToolbar.svelte +24 -21
  163. package/dist/u0-primitives/accordion/Accordion.svelte +8 -7
  164. package/dist/u0-primitives/animated-icon/AnimatedIcon.svelte +3 -3
  165. package/dist/u0-primitives/animated-icon/AnimatedIcon.test.js +82 -0
  166. package/dist/u0-primitives/avatar/Avatar.svelte +14 -14
  167. package/dist/u0-primitives/avatar/Avatar.test.js +81 -0
  168. package/dist/u0-primitives/badge/Badge.svelte +6 -4
  169. package/dist/u0-primitives/badge/ValidityBadge.svelte +4 -27
  170. package/dist/u0-primitives/button/Button.svelte +15 -12
  171. package/dist/u0-primitives/card/Card.svelte +37 -15
  172. package/dist/u0-primitives/card/Card.test.js +86 -0
  173. package/dist/u0-primitives/command-palette/CommandPalette.svelte +48 -43
  174. package/dist/u0-primitives/command-palette/CommandPalette.test.js +202 -0
  175. package/dist/u0-primitives/dropdown/Dropdown.svelte +20 -25
  176. package/dist/u0-primitives/grant-badge/GrantStatusBadge.svelte +2 -2
  177. package/dist/u0-primitives/index.d.ts +6 -0
  178. package/dist/u0-primitives/index.d.ts.map +1 -1
  179. package/dist/u0-primitives/index.js +8 -0
  180. package/dist/u0-primitives/input/Input.svelte +77 -24
  181. package/dist/u0-primitives/input/Input.svelte.d.ts +2 -10
  182. package/dist/u0-primitives/input/Input.svelte.d.ts.map +1 -1
  183. package/dist/u0-primitives/input/Input.test.js +81 -1
  184. package/dist/u0-primitives/live-dot/LiveDot.svelte +56 -0
  185. package/dist/u0-primitives/live-dot/LiveDot.svelte.d.ts +11 -0
  186. package/dist/u0-primitives/live-dot/LiveDot.svelte.d.ts.map +1 -0
  187. package/dist/u0-primitives/live-dot/LiveDot.test.js +41 -0
  188. package/dist/u0-primitives/live-dot/index.d.ts +3 -0
  189. package/dist/u0-primitives/live-dot/index.d.ts.map +1 -0
  190. package/dist/u0-primitives/live-dot/index.js +1 -0
  191. package/dist/u0-primitives/modal/Modal.svelte +22 -19
  192. package/dist/u0-primitives/modal/Modal.test.js +1 -1
  193. package/dist/u0-primitives/spinner/Spinner.svelte +11 -79
  194. package/dist/u0-primitives/spinner/Spinner.svelte.d.ts.map +1 -1
  195. package/dist/u0-primitives/steps/Steps.svelte +18 -19
  196. package/dist/u0-primitives/surface-state/SurfaceState.svelte +7 -7
  197. package/dist/u0-primitives/tabs/Tabs.svelte +13 -11
  198. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte +94 -0
  199. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte.d.ts +16 -0
  200. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.svelte.d.ts.map +1 -0
  201. package/dist/u0-primitives/theme-swatch-group/ThemeSwatchGroup.test.js +48 -0
  202. package/dist/u0-primitives/theme-swatch-group/index.d.ts +3 -0
  203. package/dist/u0-primitives/theme-swatch-group/index.d.ts.map +1 -0
  204. package/dist/u0-primitives/theme-swatch-group/index.js +1 -0
  205. package/dist/u0-primitives/toggle/Toggle.svelte +10 -11
  206. package/dist/u0-primitives/tooltip/Tooltip.svelte +9 -9
  207. package/dist/u0-primitives/web-components/button-component.d.ts +5 -1
  208. package/dist/u0-primitives/web-components/button-component.d.ts.map +1 -1
  209. package/dist/u0-primitives/web-components/button-component.js +72 -33
  210. package/dist/u0-primitives/web-components/index.d.ts +3 -0
  211. package/dist/u0-primitives/web-components/index.d.ts.map +1 -0
  212. package/dist/u0-primitives/web-components/index.js +2 -0
  213. package/dist/u0-primitives/web-components/input-component.d.ts +5 -1
  214. package/dist/u0-primitives/web-components/input-component.d.ts.map +1 -1
  215. package/dist/u0-primitives/web-components/input-component.js +56 -39
  216. package/dist/u0-primitives/web-components/web-components.test.js +96 -0
  217. package/dist/u0-primitives/window-frame/WindowFrame.svelte +87 -0
  218. package/dist/u0-primitives/window-frame/WindowFrame.svelte.d.ts +10 -0
  219. package/dist/u0-primitives/window-frame/WindowFrame.svelte.d.ts.map +1 -0
  220. package/dist/u0-primitives/window-frame/WindowFrame.test.js +31 -0
  221. package/dist/u0-primitives/window-frame/index.d.ts +3 -0
  222. package/dist/u0-primitives/window-frame/index.d.ts.map +1 -0
  223. package/dist/u0-primitives/window-frame/index.js +1 -0
  224. package/dist/x0-enchanted-blocks/components/NodepadBlock.svelte +11 -2
  225. package/dist/x0-enchanted-blocks/components/NodepadBlock.svelte.d.ts.map +1 -1
  226. package/package.json +44 -28
  227. package/src/p0-primitives/tokens/ambient.css +76 -0
  228. package/src/p0-primitives/tokens/tokens.css +124 -29
  229. package/src/p0-primitives/tokens/tokens.json +42 -24
@@ -95,7 +95,8 @@
95
95
  {/if}
96
96
  </div>
97
97
 
98
- <style>
98
+ <!-- svelte-ignore css_unused_selector -->
99
+ <style>
99
100
  .ds-block-content {
100
101
  flex: 1;
101
102
  min-height: 0;
@@ -125,40 +126,40 @@
125
126
  min-height: 2em;
126
127
  }
127
128
 
128
- /* Markdown rendered styles — scoped under :global for {@html} content */
129
- .ds-block-rendered :global(.md-h) {
129
+ /* Markdown rendered styles — scoped descendants for {@html} content */
130
+ .ds-block-rendered .md-h {
130
131
  margin: 12px 0 6px 0;
131
132
  font-weight: 600;
132
133
  color: var(--color-text-primary, #e8e0d0);
133
134
  }
134
135
 
135
- .ds-block-rendered :global(.md-h1) { font-size: 1.4em; }
136
- .ds-block-rendered :global(.md-h2) { font-size: 1.2em; }
137
- .ds-block-rendered :global(.md-h3) { font-size: 1.1em; }
138
- .ds-block-rendered :global(.md-h4),
139
- .ds-block-rendered :global(.md-h5),
140
- .ds-block-rendered :global(.md-h6) { font-size: 1em; }
136
+ .ds-block-rendered .md-h1 { font-size: 1.4em; }
137
+ .ds-block-rendered .md-h2 { font-size: 1.2em; }
138
+ .ds-block-rendered .md-h3 { font-size: 1.1em; }
139
+ .ds-block-rendered .md-h4,
140
+ .ds-block-rendered .md-h5,
141
+ .ds-block-rendered .md-h6 { font-size: 1em; }
141
142
 
142
- .ds-block-rendered :global(.md-p) {
143
+ .ds-block-rendered .md-p {
143
144
  margin: 6px 0;
144
145
  }
145
146
 
146
- .ds-block-rendered :global(.md-ul) {
147
+ .ds-block-rendered .md-ul {
147
148
  margin: 6px 0;
148
149
  padding-left: 20px;
149
150
  list-style: none;
150
151
  }
151
152
 
152
- .ds-block-rendered :global(.md-li) {
153
+ .ds-block-rendered .md-li {
153
154
  margin: 3px 0;
154
155
  }
155
156
 
156
- .ds-block-rendered :global(.md-li)::before {
157
+ .ds-block-rendered .md-li::before {
157
158
  content: '• ';
158
159
  color: var(--color-accent, var(--color-accent));
159
160
  }
160
161
 
161
- .ds-block-rendered :global(.md-bq) {
162
+ .ds-block-rendered .md-bq {
162
163
  margin: 6px 0;
163
164
  padding: 6px 10px;
164
165
  border-left: 3px solid var(--color-accent, var(--color-accent));
@@ -166,17 +167,17 @@
166
167
  font-style: italic;
167
168
  }
168
169
 
169
- .ds-block-rendered :global(.md-hr) {
170
+ .ds-block-rendered .md-hr {
170
171
  border: none;
171
172
  border-top: 1px solid var(--color-border, #333);
172
173
  margin: 12px 0;
173
174
  }
174
175
 
175
- .ds-block-rendered :global(.md-gap) {
176
+ .ds-block-rendered .md-gap {
176
177
  height: 6px;
177
178
  }
178
179
 
179
- .ds-block-rendered :global(.md-code) {
180
+ .ds-block-rendered .md-code {
180
181
  padding: 1px 5px;
181
182
  background: rgba(0, 0, 0, 0.3);
182
183
  border-radius: var(--radius-sm, 3px);
@@ -185,29 +186,29 @@
185
186
  color: var(--color-accent, var(--color-accent));
186
187
  }
187
188
 
188
- .ds-block-rendered :global(strong) {
189
+ .ds-block-rendered strong {
189
190
  font-weight: 600;
190
191
  color: var(--color-text-primary, #e8e0d0);
191
192
  }
192
193
 
193
- .ds-block-rendered :global(em) {
194
+ .ds-block-rendered em {
194
195
  font-style: italic;
195
196
  color: var(--color-text-muted, #a09880);
196
197
  }
197
198
 
198
- .ds-block-rendered :global(del) {
199
+ .ds-block-rendered del {
199
200
  text-decoration: line-through;
200
201
  color: var(--color-text-muted, #a09880);
201
202
  }
202
203
 
203
- .ds-block-rendered :global(.md-wiki) {
204
+ .ds-block-rendered .md-wiki {
204
205
  color: var(--color-accent, var(--color-accent));
205
206
  text-decoration: underline;
206
207
  text-decoration-style: dotted;
207
208
  cursor: pointer;
208
209
  }
209
210
 
210
- .ds-block-rendered :global(.md-wiki:hover) {
211
+ .ds-block-rendered .md-wiki:hover {
211
212
  text-decoration-style: solid;
212
213
  }
213
214
  </style>
@@ -1 +1 @@
1
- {"version":3,"file":"BlockContent.svelte.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/block-writer/BlockContent.svelte.ts"],"names":[],"mappings":"AAME,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAoFH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"BlockContent.svelte.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/block-writer/BlockContent.svelte.ts"],"names":[],"mappings":"AAME,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAqFH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { cleanup, fireEvent, render } from '@testing-library/svelte';
3
+ import BlockContent from './BlockContent.svelte';
4
+ const markdown = [
5
+ '# Heading',
6
+ '',
7
+ '> quote',
8
+ '',
9
+ '- alpha',
10
+ '- beta',
11
+ '',
12
+ '---',
13
+ '',
14
+ 'Use `code` and [[wiki|label]].'
15
+ ].join('\n');
16
+ describe('BlockContent', () => {
17
+ afterEach(() => cleanup());
18
+ it('renders the contenteditable editor when editing', () => {
19
+ const { container } = render(BlockContent, { isEditing: true, content: '' });
20
+ expect(container.querySelector('.ds-block-editable')).not.toBeNull();
21
+ expect(container.querySelector('.ds-block-editable')?.getAttribute('contenteditable')).toBe('true');
22
+ });
23
+ it('renders markdown as scoped rendered content when not editing', () => {
24
+ const { container } = render(BlockContent, { content: markdown });
25
+ expect(container.querySelector('.ds-block-rendered')).not.toBeNull();
26
+ expect(container.querySelector('.md-h1')?.textContent).toBe('Heading');
27
+ expect(Array.from(container.querySelectorAll('.md-li')).map(node => node.textContent)).toEqual(['alpha', 'beta']);
28
+ expect(container.querySelector('.md-bq')?.textContent).toBe('quote');
29
+ expect(container.querySelector('.md-hr')).not.toBeNull();
30
+ expect(container.querySelector('.md-code')?.textContent).toBe('code');
31
+ expect(container.querySelector('.md-wiki')?.textContent).toBe('label');
32
+ });
33
+ it('emits content changes from the editor', async () => {
34
+ const handleChange = vi.fn();
35
+ const { container } = render(BlockContent, { isEditing: true, onContentChange: handleChange });
36
+ const editor = container.querySelector('.ds-block-editable');
37
+ await fireEvent.input(editor, { target: { innerText: 'new content' } });
38
+ expect(handleChange).toHaveBeenCalledWith('new content');
39
+ });
40
+ it('blurs the editor when Escape is pressed', async () => {
41
+ const { container } = render(BlockContent, { isEditing: true });
42
+ const editor = container.querySelector('.ds-block-editable');
43
+ editor.focus();
44
+ await fireEvent.keyDown(editor, { key: 'Escape' });
45
+ expect(document.activeElement).not.toBe(editor);
46
+ });
47
+ });
@@ -41,6 +41,17 @@ export function renderMarkdown(md) {
41
41
  const lines = md.split('\n');
42
42
  const processed = [];
43
43
  for (const line of lines) {
44
+ // Blockquotes — match raw line before escaping
45
+ const bq = line.match(/^> (.+)$/);
46
+ if (bq) {
47
+ processed.push(`<blockquote class="md-bq">${renderInline(escapeHtml(bq[1]))}</blockquote>`);
48
+ continue;
49
+ }
50
+ // Horizontal rule — match raw line before escaping
51
+ if (/^[-*]{3,}$/.test(line.trim())) {
52
+ processed.push('<hr class="md-hr">');
53
+ continue;
54
+ }
44
55
  const escaped = escapeHtml(line);
45
56
  // Headings
46
57
  const hm = escaped.match(/^(#{1,6}) (.+)$/);
@@ -60,17 +71,6 @@ export function renderMarkdown(md) {
60
71
  processed.push(`<li class="md-li">${renderInline(ol[2])}</li>`);
61
72
  continue;
62
73
  }
63
- // Blockquotes
64
- const bq = escaped.match(/^> (.+)$/);
65
- if (bq) {
66
- processed.push(`<blockquote class="md-bq">${renderInline(bq[1])}</blockquote>`);
67
- continue;
68
- }
69
- // Horizontal rule
70
- if (/^[-*]{3,}$/.test(escaped.trim())) {
71
- processed.push('<hr class="md-hr">');
72
- continue;
73
- }
74
74
  // Empty line
75
75
  if (escaped.trim() === '') {
76
76
  processed.push('<div class="md-gap"></div>');
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { renderMarkdown, renderInlineMarkdown } from './markdown';
3
+ describe('block-writer/renderMarkdown', () => {
4
+ it('returns empty string for empty input', () => {
5
+ expect(renderMarkdown('')).toBe('');
6
+ });
7
+ it('renders headings h1–h6', () => {
8
+ expect(renderMarkdown('# H1')).toContain('<h1 class="md-h md-h1">H1</h1>');
9
+ expect(renderMarkdown('## H2')).toContain('<h2 class="md-h md-h2">H2</h2>');
10
+ expect(renderMarkdown('###### H6')).toContain('<h6 class="md-h md-h6">H6</h6>');
11
+ });
12
+ it('renders blockquotes', () => {
13
+ const html = renderMarkdown('> important quote');
14
+ expect(html).toContain('<blockquote class="md-bq">important quote</blockquote>');
15
+ });
16
+ it('escapes HTML entities inside blockquotes', () => {
17
+ const html = renderMarkdown('<script>alert(1)</script>');
18
+ expect(html).not.toContain('<script>');
19
+ expect(html).toContain('&lt;script&gt;');
20
+ });
21
+ it('renders unordered list items grouped in ul', () => {
22
+ const html = renderMarkdown('- a\n- b\n- c');
23
+ expect(html).toContain('<ul class="md-ul">');
24
+ expect(html).toContain('<li class="md-li">a</li>');
25
+ expect(html).toContain('<li class="md-li">b</li>');
26
+ expect(html).toContain('<li class="md-li">c</li>');
27
+ });
28
+ it('renders ordered list items grouped in ul', () => {
29
+ const html = renderMarkdown('1. first\n2. second');
30
+ expect(html).toContain('<ul class="md-ul">');
31
+ expect(html).toContain('<li class="md-li">first</li>');
32
+ expect(html).toContain('<li class="md-li">second</li>');
33
+ });
34
+ it('renders horizontal rules', () => {
35
+ expect(renderMarkdown('---')).toContain('<hr class="md-hr">');
36
+ expect(renderMarkdown('***')).toContain('<hr class="md-hr">');
37
+ });
38
+ it('renders paragraphs for plain text', () => {
39
+ const html = renderMarkdown('just some text');
40
+ expect(html).toContain('<p class="md-p">just some text</p>');
41
+ });
42
+ it('renders inline code', () => {
43
+ const html = renderMarkdown('Use `console.log` for debugging');
44
+ expect(html).toContain('<code class="md-code">console.log</code>');
45
+ });
46
+ it('renders wikilinks', () => {
47
+ const html = renderMarkdown('See [[Target Page]]');
48
+ expect(html).toContain('<span class="md-wiki">Target Page</span>');
49
+ });
50
+ it('renders labeled wikilinks', () => {
51
+ const html = renderMarkdown('See [[Target Page|display text]]');
52
+ expect(html).toContain('<span class="md-wiki">display text</span>');
53
+ });
54
+ it('renders bold and italic', () => {
55
+ expect(renderMarkdown('**bold**')).toContain('<strong>bold</strong>');
56
+ expect(renderMarkdown('*italic*')).toContain('<em>italic</em>');
57
+ });
58
+ it('renders strikethrough', () => {
59
+ expect(renderMarkdown('~~deleted~~')).toContain('<del>deleted</del>');
60
+ });
61
+ it('renders empty lines as gap divs', () => {
62
+ expect(renderMarkdown('')).toBe('');
63
+ const html = renderMarkdown('before\n\nafter');
64
+ expect(html).toContain('<div class="md-gap"></div>');
65
+ });
66
+ });
67
+ describe('block-writer/renderInlineMarkdown', () => {
68
+ it('returns empty string for empty input', () => {
69
+ expect(renderInlineMarkdown('')).toBe('');
70
+ });
71
+ it('renders inline markdown without block elements', () => {
72
+ const html = renderInlineMarkdown('**bold** and `code`');
73
+ expect(html).toContain('<strong>bold</strong>');
74
+ expect(html).toContain('<code class="md-code">code</code>');
75
+ });
76
+ it('escapes HTML entities', () => {
77
+ const html = renderInlineMarkdown('<em>tag</em>');
78
+ expect(html).not.toContain('<em>tag</em>');
79
+ expect(html).toContain('&lt;em&gt;tag&lt;/em&gt;');
80
+ });
81
+ });
@@ -0,0 +1,87 @@
1
+ <script lang="ts">
2
+ import Card from '../../u0-primitives/card/Card.svelte';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ export interface Props {
6
+ class?: string;
7
+ children?: Snippet;
8
+ }
9
+
10
+ let {
11
+ class: className = '',
12
+ children
13
+ }: Props = $props();
14
+ </script>
15
+
16
+ <div class="ds-stacked-card {className}">
17
+ <div class="ds-stacked-card-sheet sheet-back-2" aria-hidden="true"></div>
18
+ <div class="ds-stacked-card-sheet sheet-back-1" aria-hidden="true"></div>
19
+ <div class="ds-stacked-card-sheet sheet-front">
20
+ <Card variant="elevated">
21
+ {#if children}
22
+ {@render children()}
23
+ {/if}
24
+ </Card>
25
+ </div>
26
+ </div>
27
+
28
+ <style>
29
+ .ds-stacked-card {
30
+ position: relative;
31
+ /* The rotated back sheets are calibrated for a compact card, not a
32
+ full-bleed block — at very wide containers the rotation angle
33
+ translates to a large vertical skew. Cap width by default; override
34
+ via the class prop if a different size is genuinely wanted. */
35
+ max-width: 30rem;
36
+ }
37
+
38
+ .ds-stacked-card-sheet {
39
+ border: var(--border-width-thin) solid var(--border-default);
40
+ }
41
+
42
+ .sheet-back-1,
43
+ .sheet-back-2 {
44
+ position: absolute;
45
+ inset: 0;
46
+ z-index: 0;
47
+ transition: transform var(--transition-normal);
48
+ }
49
+
50
+ .sheet-back-1 {
51
+ background: var(--color-accent-subtle);
52
+ border-color: var(--color-accent-muted);
53
+ transform: rotate(-2deg) translate(10px, 12px);
54
+ }
55
+
56
+ .sheet-back-2 {
57
+ background: var(--overlay-white-04);
58
+ transform: rotate(2deg) translate(-8px, 10px);
59
+ }
60
+
61
+ .sheet-front {
62
+ position: relative;
63
+ z-index: 1;
64
+ box-shadow: var(--shadow-sm);
65
+ transition: transform var(--transition-normal), box-shadow var(--transition-normal);
66
+ }
67
+
68
+ .ds-stacked-card:hover .sheet-back-1 {
69
+ transform: rotate(-3deg) translate(14px, 16px);
70
+ }
71
+
72
+ .ds-stacked-card:hover .sheet-back-2 {
73
+ transform: rotate(3deg) translate(-11px, 14px);
74
+ }
75
+
76
+ .ds-stacked-card:hover .sheet-front {
77
+ transform: translateY(-3px);
78
+ }
79
+
80
+ @media (prefers-reduced-motion: reduce) {
81
+ .sheet-back-1,
82
+ .sheet-back-2,
83
+ .sheet-front {
84
+ transition: none;
85
+ }
86
+ }
87
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface Props {
3
+ class?: string;
4
+ children?: Snippet;
5
+ }
6
+ declare const StackedCard: import("svelte").Component<Props, {}, "">;
7
+ type StackedCard = ReturnType<typeof StackedCard>;
8
+ export default StackedCard;
9
+ //# sourceMappingURL=StackedCard.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StackedCard.svelte.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/card/StackedCard.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,MAAM,WAAW,KAAK;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA4BH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { afterEach, describe, it, expect } from 'vitest';
2
+ import { cleanup, render } from '@testing-library/svelte';
3
+ import { createRawSnippet } from 'svelte';
4
+ import StackedCard from './StackedCard.svelte';
5
+ const textSnippet = (text) => createRawSnippet(() => ({ render: () => `<span>${text}</span>` }));
6
+ describe('StackedCard', () => {
7
+ afterEach(() => cleanup());
8
+ it('renders three stacked sheets', () => {
9
+ const { container } = render(StackedCard);
10
+ expect(container.querySelectorAll('.ds-stacked-card-sheet')).toHaveLength(3);
11
+ });
12
+ it('hides the decorative back sheets from assistive tech', () => {
13
+ const { container } = render(StackedCard);
14
+ expect(container.querySelector('.sheet-back-1')?.getAttribute('aria-hidden')).toBe('true');
15
+ expect(container.querySelector('.sheet-back-2')?.getAttribute('aria-hidden')).toBe('true');
16
+ });
17
+ it('renders children inside the front sheet', () => {
18
+ const { container, getByText } = render(StackedCard, {
19
+ children: textSnippet('Evidence panel')
20
+ });
21
+ const front = container.querySelector('.sheet-front');
22
+ expect(front).not.toBeNull();
23
+ expect(getByText('Evidence panel')).toBeDefined();
24
+ });
25
+ it('renders an underlying Card in the front sheet', () => {
26
+ const { container } = render(StackedCard);
27
+ expect(container.querySelector('.sheet-front .ds-card')).not.toBeNull();
28
+ });
29
+ });
@@ -1,3 +1,4 @@
1
+ export { default as StackedCard } from './card/StackedCard.svelte';
1
2
  export { default as WorkspaceLayout } from './workspace/WorkspaceLayout.svelte';
2
3
  export { default as ChatViewLayout } from './chat-view/ChatViewLayout.svelte';
3
4
  export { default as KanbanViewLayout } from './kanban/KanbanViewLayout.svelte';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/l0-layout/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9E,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,YAAY,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,qBAAqB,CAAC;AAG7B,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGhF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/l0-layout/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9E,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,YAAY,EACV,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,qBAAqB,CAAC;AAG7B,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGhF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  // L0 Layout — Layout composition templates
2
+ export { default as StackedCard } from './card/StackedCard.svelte';
2
3
  export { default as WorkspaceLayout } from './workspace/WorkspaceLayout.svelte';
3
4
  export { default as ChatViewLayout } from './chat-view/ChatViewLayout.svelte';
4
5
  export { default as KanbanViewLayout } from './kanban/KanbanViewLayout.svelte';
@@ -246,7 +246,7 @@
246
246
 
247
247
  .ds-kanban-move-toast {
248
248
  padding: var(--space-2) var(--space-5);
249
- background: var(--color-accent-faint, rgba(184,115,51,0.1));
249
+ background: var(--color-accent-faint, rgba(128,128,128,0.08));
250
250
  border-bottom: var(--border-width-thin) solid var(--border-subtle);
251
251
  color: var(--color-text-secondary);
252
252
  font-size: var(--text-sm);
@@ -253,7 +253,7 @@
253
253
  }
254
254
 
255
255
  .ds-kanban-column-content.is-drag-target {
256
- background: var(--color-accent-faint, rgba(184,115,51,0.06));
256
+ background: var(--color-accent-faint, rgba(128,128,128,0.05));
257
257
  }
258
258
 
259
259
  .ds-kanban-drop-indicator {
@@ -7,10 +7,11 @@
7
7
  import { Canvas, Layer } from 'svelte-canvas';
8
8
  import { getArrow } from 'perfect-arrows';
9
9
  import type { GraphSnapshot, GraphStateApi } from './types.js';
10
+ import type { CanvasTheme } from '../p0-primitives/canvas-theme';
10
11
  import { GraphState } from './graph-state.svelte.js';
11
12
  import { runLayout } from './layout.js';
12
13
  import { EDGE_REVEAL_STAGGER_MS } from './types.js';
13
- import { getCanvasTheme } from '../p0-primitives/canvas-theme';
14
+ import { getCanvasTheme } from '../p0-primitives/canvas-theme';
14
15
 
15
16
  // ── Props ────────────────────────────────────────────────────────────────────
16
17
 
@@ -89,6 +90,18 @@
89
90
 
90
91
  const NODE_RADIUS = 4;
91
92
  const FONT = '12px var(--font-mono, monospace)';
93
+ const BADGE_FONT = '10px var(--font-mono, monospace)';
94
+
95
+ function statusColors(status: unknown, theme: CanvasTheme) {
96
+ switch (status) {
97
+ case 'Running': return { fill: theme.quaternion.j + '22', stroke: theme.quaternion.j, label: theme.quaternion.j };
98
+ case 'Passed': return { fill: theme.quaternion.j + '18', stroke: theme.quaternion.j, label: theme.quaternion.j };
99
+ case 'Failed': return { fill: theme.severity.critical + '22', stroke: theme.severity.critical, label: theme.severity.critical };
100
+ case 'Crashed': return { fill: theme.severity.critical + '22', stroke: theme.severity.critical, label: theme.severity.critical };
101
+ case 'Skipped': return { fill: theme.node, stroke: theme.severity.minor, label: theme.severity.minor };
102
+ default: return { fill: theme.node, stroke: theme.nodeBorder, label: theme.nodeText };
103
+ }
104
+ }
92
105
 
93
106
  // ── Render ──────────────────────────────────────────────────────────────────
94
107
 
@@ -165,10 +178,12 @@
165
178
 
166
179
  const isFocus = node.id === focusId;
167
180
  const { x, y, width: w, height: h } = pos;
181
+ const status = node.data?.['status'];
182
+ const { fill, stroke, label: labelColor } = statusColors(status, COLORS);
168
183
 
169
184
  // Node body
170
- context.fillStyle = isFocus ? COLORS.focus : COLORS.node;
171
- context.strokeStyle = COLORS.nodeBorder;
185
+ context.fillStyle = isFocus ? COLORS.focus : fill;
186
+ context.strokeStyle = isFocus ? COLORS.focus : stroke;
172
187
  context.lineWidth = isFocus ? 2 : 1;
173
188
 
174
189
  context.beginPath();
@@ -177,14 +192,43 @@
177
192
  context.stroke();
178
193
 
179
194
  // Label
180
- context.fillStyle = COLORS.nodeText;
195
+ context.fillStyle = isFocus ? '#000' : labelColor;
181
196
  context.font = FONT;
182
197
  context.textAlign = 'center';
183
198
  context.textBaseline = 'middle';
184
- // Truncate if needed
185
199
  const maxWidth = w - 16;
186
- const label = node.label.length > 18 ? node.label.slice(0, 16) + '…' : node.label;
200
+ const label = node.label.length > 20 ? node.label.slice(0, 18) + '…' : node.label;
187
201
  context.fillText(label, x + w / 2, y + h / 2, maxWidth);
202
+
203
+ // Error indicator
204
+ if (node.data?.['error']) {
205
+ context.fillStyle = COLORS.severity.critical;
206
+ context.font = '11px var(--font-mono, monospace)';
207
+ context.textAlign = 'right';
208
+ context.textBaseline = 'top';
209
+ context.fillText('⚠', x + w - 4, y + 4);
210
+ }
211
+
212
+ // Attempt badge (when > 1)
213
+ const attempt = node.data?.['attempt'];
214
+ if (typeof attempt === 'number' && attempt > 1) {
215
+ const badge = `#${attempt}`;
216
+ context.font = BADGE_FONT;
217
+ const bw = context.measureText(badge).width + 8;
218
+ const bh = 14;
219
+ const bx = x + w - bw - 4;
220
+ const by = y + h - bh - 4;
221
+
222
+ context.fillStyle = COLORS.accentRamp.solid;
223
+ context.beginPath();
224
+ context.roundRect(bx, by, bw, bh, 3);
225
+ context.fill();
226
+
227
+ context.fillStyle = '#000';
228
+ context.textAlign = 'center';
229
+ context.textBaseline = 'middle';
230
+ context.fillText(badge, bx + bw / 2, by + bh / 2);
231
+ }
188
232
  }
189
233
  }
190
234
  </script>
@@ -1 +1 @@
1
- {"version":3,"file":"FlowCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/n1-flow-canvas/FlowCanvas.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAS7D,UAAU,KAAK;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA8LH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"FlowCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/n1-flow-canvas/FlowCanvas.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAU7D,UAAU,KAAK;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0OH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -3,4 +3,6 @@ export { EDGE_REVEAL_STAGGER_MS } from './types.js';
3
3
  export { default as FlowCanvas } from './FlowCanvas.svelte';
4
4
  export { GraphState } from './graph-state.svelte';
5
5
  export { nodeHitTest, domEventToCanvasCoords, parseMentionEdges, parseGroupedSequenceEdges } from './utils.js';
6
+ export { pipelineStateToSnapshot, createEmptyPipelineSnapshot, PIPELINE_STAGE_NAMES, } from './pipeline-adapter.js';
7
+ export type { PipelineState, PipelineStageData, PipelineStatus, PipelineTermination, } from './pipeline-adapter.js';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/n1-flow-canvas/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/n1-flow-canvas/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC/G,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,uBAAuB,CAAC"}
@@ -4,3 +4,4 @@ export { EDGE_REVEAL_STAGGER_MS } from './types.js';
4
4
  export { default as FlowCanvas } from './FlowCanvas.svelte';
5
5
  export { GraphState } from './graph-state.svelte';
6
6
  export { nodeHitTest, domEventToCanvasCoords, parseMentionEdges, parseGroupedSequenceEdges } from './utils.js';
7
+ export { pipelineStateToSnapshot, createEmptyPipelineSnapshot, PIPELINE_STAGE_NAMES, } from './pipeline-adapter.js';
@@ -0,0 +1,37 @@
1
+ import type { GraphSnapshot } from './types.js';
2
+ export interface PipelineTermination {
3
+ reason: string;
4
+ final_tokens: number;
5
+ }
6
+ export interface PipelineStageData {
7
+ id: string;
8
+ name: string;
9
+ status: PipelineStatus;
10
+ attempt: number;
11
+ selected_model: string | null;
12
+ termination: PipelineTermination | null;
13
+ artifact_path: string | null;
14
+ error: string | null;
15
+ locked_by: string | null;
16
+ started_at: string | null;
17
+ completed_at: string | null;
18
+ }
19
+ export type PipelineStatus = 'Pending' | 'Running' | 'Passed' | 'Failed' | 'Skipped' | 'Crashed';
20
+ export interface PipelineState {
21
+ run_id: string;
22
+ task_id: string;
23
+ requested_id: string;
24
+ base_main_sha: string | null;
25
+ prior_tos_status: string | null;
26
+ worktree_path: string | null;
27
+ stages: PipelineStageData[];
28
+ remediation_count: number;
29
+ max_remediation: number;
30
+ locked_by: string;
31
+ created_at: string;
32
+ updated_at: string;
33
+ }
34
+ export declare const PIPELINE_STAGE_NAMES: string[];
35
+ export declare function pipelineStateToSnapshot(state: PipelineState): GraphSnapshot;
36
+ export declare function createEmptyPipelineSnapshot(): GraphSnapshot;
37
+ //# sourceMappingURL=pipeline-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-adapter.d.ts","sourceRoot":"","sources":["../../src/n1-flow-canvas/pipeline-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,YAAY,CAAC;AAItE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACxC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjG,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AA0CD,eAAO,MAAM,oBAAoB,UAA6D,CAAC;AAE/F,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAiG3E;AAcD,wBAAgB,2BAA2B,IAAI,aAAa,CAe3D"}