@caddis/cli 0.4.45 → 0.4.47

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 (193) hide show
  1. package/bundles/antigravity-plugin/plugin.json +1 -1
  2. package/bundles/antigravity-plugin/skills/flow-studio/README.md +46 -7
  3. package/bundles/antigravity-plugin/skills/flow-studio/SKILL.md +81 -81
  4. package/bundles/antigravity-plugin/skills/flow-studio/examples/README.md +8 -0
  5. package/bundles/antigravity-plugin/skills/flow-studio/examples/agent-journey.json +103 -0
  6. package/bundles/antigravity-plugin/skills/flow-studio/examples/approval-flow.json +134 -0
  7. package/bundles/antigravity-plugin/skills/flow-studio/examples/ci-cd-pipeline.json +132 -0
  8. package/bundles/antigravity-plugin/skills/flow-studio/examples/incident-timeline.json +109 -0
  9. package/bundles/antigravity-plugin/skills/flow-studio/examples/order-desk.json +99 -0
  10. package/bundles/antigravity-plugin/skills/flow-studio/examples/service-map.json +133 -0
  11. package/bundles/antigravity-plugin/skills/flow-studio/examples/state-machine.json +106 -0
  12. package/bundles/antigravity-plugin/skills/flow-studio/examples/ticket-lifecycle.json +107 -0
  13. package/bundles/antigravity-plugin/skills/flow-studio/model.schema.json +27 -8
  14. package/bundles/antigravity-plugin/skills/flow-studio/react/FlowStudioView.test.tsx +82 -0
  15. package/bundles/antigravity-plugin/skills/flow-studio/react/FlowStudioView.tsx +67 -0
  16. package/bundles/antigravity-plugin/skills/flow-studio/react/README.md +37 -0
  17. package/bundles/antigravity-plugin/skills/flow-studio/react/index.ts +3 -0
  18. package/bundles/antigravity-plugin/skills/flow-studio/react/native/FlowCanvas.tsx +58 -0
  19. package/bundles/antigravity-plugin/skills/flow-studio/react/native/Inspector.tsx +27 -0
  20. package/bundles/antigravity-plugin/skills/flow-studio/react/native/index.ts +6 -0
  21. package/bundles/antigravity-plugin/skills/flow-studio/react/native/native.css +18 -0
  22. package/bundles/antigravity-plugin/skills/flow-studio/react/native/native.test.tsx +161 -0
  23. package/bundles/antigravity-plugin/skills/flow-studio/react/native/useFlowGeometry.ts +22 -0
  24. package/bundles/antigravity-plugin/skills/flow-studio/react/native/useTrace.ts +29 -0
  25. package/bundles/antigravity-plugin/skills/flow-studio/react/native/useViewport.ts +75 -0
  26. package/bundles/antigravity-plugin/skills/flow-studio/react/states.tsx +13 -0
  27. package/bundles/antigravity-plugin/skills/flow-studio/references/design-language.md +177 -0
  28. package/bundles/antigravity-plugin/skills/flow-studio/references/implement-in-app.md +213 -0
  29. package/bundles/antigravity-plugin/skills/flow-studio/references/model-schema.md +254 -0
  30. package/bundles/antigravity-plugin/skills/flow-studio/references/notes-and-spec.md +74 -0
  31. package/bundles/antigravity-plugin/skills/flow-studio/references/patterns.md +385 -49
  32. package/bundles/antigravity-plugin/skills/flow-studio/references/ux-rules.md +91 -0
  33. package/bundles/antigravity-plugin/skills/flow-studio/references/verify.md +124 -0
  34. package/bundles/antigravity-plugin/skills/flow-studio/scripts/build-engine.mjs +54 -14
  35. package/bundles/antigravity-plugin/skills/flow-studio/scripts/build.mjs +21 -4
  36. package/bundles/antigravity-plugin/skills/flow-studio/scripts/check.mjs +320 -28
  37. package/bundles/antigravity-plugin/skills/flow-studio/scripts/default-notes.json +67 -0
  38. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/auto-entry-guard.mjs +5 -0
  39. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/auto-entry-guard.test.mjs +14 -0
  40. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/auto-entry.test.mjs +31 -0
  41. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/build-engine.test.mjs +30 -2
  42. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/check-args.mjs +18 -0
  43. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/check-args.test.mjs +15 -0
  44. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/check-selftest.test.mjs +64 -4
  45. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/cli.test.mjs +115 -0
  46. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/demo-pack.mjs +23 -0
  47. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/demo-pack.test.mjs +34 -0
  48. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/docs.test.mjs +128 -0
  49. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/library.test.mjs +26 -0
  50. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/react-proof-cleanup.mjs +12 -0
  51. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/react-proof-cleanup.test.mjs +45 -0
  52. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/react-proof-page.mjs +3 -0
  53. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/react-proof-page.test.mjs +9 -0
  54. package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/styles.test.mjs +37 -0
  55. package/bundles/antigravity-plugin/skills/flow-studio/scripts/react-proof.mjs +92 -0
  56. package/bundles/antigravity-plugin/skills/flow-studio/scripts/validate.mjs +5 -1
  57. package/bundles/antigravity-plugin/skills/flow-studio/src/autolayout.test.ts +78 -0
  58. package/bundles/antigravity-plugin/skills/flow-studio/src/autolayout.ts +132 -0
  59. package/bundles/antigravity-plugin/skills/flow-studio/src/chrome.ts +11 -7
  60. package/bundles/antigravity-plugin/skills/flow-studio/src/controls.ts +8 -0
  61. package/bundles/antigravity-plugin/skills/flow-studio/src/ctx.ts +16 -0
  62. package/bundles/antigravity-plugin/skills/flow-studio/src/diff.test.ts +31 -0
  63. package/bundles/antigravity-plugin/skills/flow-studio/src/diff.ts +34 -0
  64. package/bundles/antigravity-plugin/skills/flow-studio/src/engine.ts +83 -32
  65. package/bundles/antigravity-plugin/skills/flow-studio/src/inspector.ts +23 -5
  66. package/bundles/antigravity-plugin/skills/flow-studio/src/interact.ts +21 -8
  67. package/bundles/antigravity-plugin/skills/flow-studio/src/layout.test.ts +75 -0
  68. package/bundles/antigravity-plugin/skills/flow-studio/src/layout.ts +49 -11
  69. package/bundles/antigravity-plugin/skills/flow-studio/src/lib.ts +20 -0
  70. package/bundles/antigravity-plugin/skills/flow-studio/src/metrics.test.ts +57 -0
  71. package/bundles/antigravity-plugin/skills/flow-studio/src/metrics.ts +29 -0
  72. package/bundles/antigravity-plugin/skills/flow-studio/src/model.test.ts +62 -2
  73. package/bundles/antigravity-plugin/skills/flow-studio/src/model.ts +101 -16
  74. package/bundles/antigravity-plugin/skills/flow-studio/src/notes.ts +8 -0
  75. package/bundles/antigravity-plugin/skills/flow-studio/src/page.ts +21 -0
  76. package/bundles/antigravity-plugin/skills/flow-studio/src/playback.test.ts +104 -0
  77. package/bundles/antigravity-plugin/skills/flow-studio/src/playback.ts +106 -0
  78. package/bundles/antigravity-plugin/skills/flow-studio/src/playbackui.ts +193 -0
  79. package/bundles/antigravity-plugin/skills/flow-studio/src/render.ts +66 -18
  80. package/bundles/antigravity-plugin/skills/flow-studio/src/routing.test.ts +21 -1
  81. package/bundles/antigravity-plugin/skills/flow-studio/src/routing.ts +32 -0
  82. package/bundles/antigravity-plugin/skills/flow-studio/src/rules.test.ts +48 -1
  83. package/bundles/antigravity-plugin/skills/flow-studio/src/rules.ts +52 -1
  84. package/bundles/antigravity-plugin/skills/flow-studio/src/selection.test.ts +12 -0
  85. package/bundles/antigravity-plugin/skills/flow-studio/src/selection.ts +4 -0
  86. package/bundles/antigravity-plugin/skills/flow-studio/src/stateCss.test.ts +7 -0
  87. package/bundles/antigravity-plugin/skills/flow-studio/src/stateCss.ts +1 -0
  88. package/bundles/antigravity-plugin/skills/flow-studio/src/styles.css +44 -10
  89. package/bundles/antigravity-plugin/skills/flow-studio/src/trace.test.ts +21 -1
  90. package/bundles/antigravity-plugin/skills/flow-studio/src/trace.ts +18 -0
  91. package/bundles/antigravity-plugin/skills/flow-studio/templates/engine.html +995 -82
  92. package/bundles/antigravity-plugin/skills/flow-studio/templates/engine.shell.html +1 -39
  93. package/bundles/antigravity-plugin/skills/flow-studio/templates/flow-studio.css +191 -0
  94. package/bundles/antigravity-plugin/skills/flow-studio/templates/flow-studio.lib.d.mts +1 -0
  95. package/bundles/antigravity-plugin/skills/flow-studio/templates/flow-studio.lib.mjs +2492 -0
  96. package/bundles/antigravity-plugin/skills/flow-studio/templates/shell-body.html +50 -0
  97. package/bundles/codex/.codex/skills/frontend/flow-studio/README.md +46 -7
  98. package/bundles/codex/.codex/skills/frontend/flow-studio/SKILL.md +81 -81
  99. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/README.md +8 -0
  100. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/agent-journey.json +103 -0
  101. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/approval-flow.json +134 -0
  102. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/ci-cd-pipeline.json +132 -0
  103. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/incident-timeline.json +109 -0
  104. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/order-desk.json +99 -0
  105. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/service-map.json +133 -0
  106. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/state-machine.json +106 -0
  107. package/bundles/codex/.codex/skills/frontend/flow-studio/examples/ticket-lifecycle.json +107 -0
  108. package/bundles/codex/.codex/skills/frontend/flow-studio/model.schema.json +27 -8
  109. package/bundles/codex/.codex/skills/frontend/flow-studio/react/FlowStudioView.test.tsx +82 -0
  110. package/bundles/codex/.codex/skills/frontend/flow-studio/react/FlowStudioView.tsx +67 -0
  111. package/bundles/codex/.codex/skills/frontend/flow-studio/react/README.md +37 -0
  112. package/bundles/codex/.codex/skills/frontend/flow-studio/react/index.ts +3 -0
  113. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/FlowCanvas.tsx +58 -0
  114. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/Inspector.tsx +27 -0
  115. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/index.ts +6 -0
  116. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/native.css +18 -0
  117. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/native.test.tsx +161 -0
  118. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/useFlowGeometry.ts +22 -0
  119. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/useTrace.ts +29 -0
  120. package/bundles/codex/.codex/skills/frontend/flow-studio/react/native/useViewport.ts +75 -0
  121. package/bundles/codex/.codex/skills/frontend/flow-studio/react/states.tsx +13 -0
  122. package/bundles/codex/.codex/skills/frontend/flow-studio/references/design-language.md +177 -0
  123. package/bundles/codex/.codex/skills/frontend/flow-studio/references/implement-in-app.md +213 -0
  124. package/bundles/codex/.codex/skills/frontend/flow-studio/references/model-schema.md +254 -0
  125. package/bundles/codex/.codex/skills/frontend/flow-studio/references/notes-and-spec.md +74 -0
  126. package/bundles/codex/.codex/skills/frontend/flow-studio/references/patterns.md +385 -49
  127. package/bundles/codex/.codex/skills/frontend/flow-studio/references/ux-rules.md +91 -0
  128. package/bundles/codex/.codex/skills/frontend/flow-studio/references/verify.md +124 -0
  129. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/build-engine.mjs +54 -14
  130. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/build.mjs +21 -4
  131. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/check.mjs +320 -28
  132. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/default-notes.json +67 -0
  133. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/auto-entry-guard.mjs +5 -0
  134. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/auto-entry-guard.test.mjs +14 -0
  135. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/auto-entry.test.mjs +31 -0
  136. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/build-engine.test.mjs +30 -2
  137. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/check-args.mjs +18 -0
  138. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/check-args.test.mjs +15 -0
  139. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/check-selftest.test.mjs +64 -4
  140. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/cli.test.mjs +115 -0
  141. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/demo-pack.mjs +23 -0
  142. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/demo-pack.test.mjs +34 -0
  143. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/docs.test.mjs +128 -0
  144. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/library.test.mjs +26 -0
  145. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/react-proof-cleanup.mjs +12 -0
  146. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/react-proof-cleanup.test.mjs +45 -0
  147. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/react-proof-page.mjs +3 -0
  148. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/react-proof-page.test.mjs +9 -0
  149. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/styles.test.mjs +37 -0
  150. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/react-proof.mjs +92 -0
  151. package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/validate.mjs +5 -1
  152. package/bundles/codex/.codex/skills/frontend/flow-studio/src/autolayout.test.ts +78 -0
  153. package/bundles/codex/.codex/skills/frontend/flow-studio/src/autolayout.ts +132 -0
  154. package/bundles/codex/.codex/skills/frontend/flow-studio/src/chrome.ts +11 -7
  155. package/bundles/codex/.codex/skills/frontend/flow-studio/src/controls.ts +8 -0
  156. package/bundles/codex/.codex/skills/frontend/flow-studio/src/ctx.ts +16 -0
  157. package/bundles/codex/.codex/skills/frontend/flow-studio/src/diff.test.ts +31 -0
  158. package/bundles/codex/.codex/skills/frontend/flow-studio/src/diff.ts +34 -0
  159. package/bundles/codex/.codex/skills/frontend/flow-studio/src/engine.ts +83 -32
  160. package/bundles/codex/.codex/skills/frontend/flow-studio/src/inspector.ts +23 -5
  161. package/bundles/codex/.codex/skills/frontend/flow-studio/src/interact.ts +21 -8
  162. package/bundles/codex/.codex/skills/frontend/flow-studio/src/layout.test.ts +75 -0
  163. package/bundles/codex/.codex/skills/frontend/flow-studio/src/layout.ts +49 -11
  164. package/bundles/codex/.codex/skills/frontend/flow-studio/src/lib.ts +20 -0
  165. package/bundles/codex/.codex/skills/frontend/flow-studio/src/metrics.test.ts +57 -0
  166. package/bundles/codex/.codex/skills/frontend/flow-studio/src/metrics.ts +29 -0
  167. package/bundles/codex/.codex/skills/frontend/flow-studio/src/model.test.ts +62 -2
  168. package/bundles/codex/.codex/skills/frontend/flow-studio/src/model.ts +101 -16
  169. package/bundles/codex/.codex/skills/frontend/flow-studio/src/notes.ts +8 -0
  170. package/bundles/codex/.codex/skills/frontend/flow-studio/src/page.ts +21 -0
  171. package/bundles/codex/.codex/skills/frontend/flow-studio/src/playback.test.ts +104 -0
  172. package/bundles/codex/.codex/skills/frontend/flow-studio/src/playback.ts +106 -0
  173. package/bundles/codex/.codex/skills/frontend/flow-studio/src/playbackui.ts +193 -0
  174. package/bundles/codex/.codex/skills/frontend/flow-studio/src/render.ts +66 -18
  175. package/bundles/codex/.codex/skills/frontend/flow-studio/src/routing.test.ts +21 -1
  176. package/bundles/codex/.codex/skills/frontend/flow-studio/src/routing.ts +32 -0
  177. package/bundles/codex/.codex/skills/frontend/flow-studio/src/rules.test.ts +48 -1
  178. package/bundles/codex/.codex/skills/frontend/flow-studio/src/rules.ts +52 -1
  179. package/bundles/codex/.codex/skills/frontend/flow-studio/src/selection.test.ts +12 -0
  180. package/bundles/codex/.codex/skills/frontend/flow-studio/src/selection.ts +4 -0
  181. package/bundles/codex/.codex/skills/frontend/flow-studio/src/stateCss.test.ts +7 -0
  182. package/bundles/codex/.codex/skills/frontend/flow-studio/src/stateCss.ts +1 -0
  183. package/bundles/codex/.codex/skills/frontend/flow-studio/src/styles.css +44 -10
  184. package/bundles/codex/.codex/skills/frontend/flow-studio/src/trace.test.ts +21 -1
  185. package/bundles/codex/.codex/skills/frontend/flow-studio/src/trace.ts +18 -0
  186. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/engine.html +995 -82
  187. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/engine.shell.html +1 -39
  188. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/flow-studio.css +191 -0
  189. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/flow-studio.lib.d.mts +1 -0
  190. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/flow-studio.lib.mjs +2492 -0
  191. package/bundles/codex/.codex/skills/frontend/flow-studio/templates/shell-body.html +50 -0
  192. package/bundles/manifest.json +2 -2
  193. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  :root {
2
2
  --bg:#f6f8fa; --panel:#ffffff; --panel2:#f6f8fa; --edge:#d0d7de; --rule:#d8dee4; --fg:#1f2328; --muted:#59636e;
3
3
  --accent:#0969da; --accent-solid:#0969da; --ok:#1a7f37; --warn:#9a6700; --crit:#cf222e; --glow:rgba(9,105,218,.22);
4
- --up:#0a7ea4; --down:#8250df; --shadow:0 1px 0 rgba(31,35,40,.04), 0 6px 18px rgba(31,35,40,.08); --grid:rgba(31,35,40,.035);
4
+ --up:#0a7ea4; --down:#8250df; --shadow:0 1px 0 rgba(31,35,40,.04), 0 6px 18px rgba(31,35,40,.08); --grid:rgba(31,35,40,.035); --dot:rgba(31,35,40,.18); --dot-size:1.2px; --dot-gap:24px; --edge-w:1.1px; --edge-w-hot:1.5px; --edge-w-play:1.6px; --trail-w:1.8px; --ripple-w:2px;
5
5
  --warn-bg:rgba(154,103,0,.10); --ok-bg:rgba(26,127,55,.10); --crit-bg:rgba(207,34,46,.08); --info-bg:rgba(9,105,218,.10);
6
6
  --mono:"IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
7
7
  }
@@ -9,14 +9,14 @@
9
9
  :root:not([data-theme="light"]) {
10
10
  --bg:#0d1117; --panel:#161b22; --panel2:#0d1117; --edge:#30363d; --rule:#2b323a; --fg:#e6edf3; --muted:#9198a1;
11
11
  --accent:#4493f8; --accent-solid:#1f6feb; --ok:#3fb950; --warn:#d29922; --crit:#f85149; --glow:rgba(68,147,248,.35);
12
- --up:#6fcbe6; --down:#d0a0ee; --shadow:0 1px 0 rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.45); --grid:rgba(255,255,255,.04);
12
+ --up:#6fcbe6; --down:#d0a0ee; --shadow:0 1px 0 rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.45); --grid:rgba(255,255,255,.04); --dot:rgba(255,255,255,.16);
13
13
  --warn-bg:rgba(210,153,34,.14); --ok-bg:rgba(63,185,80,.12); --crit-bg:rgba(248,81,73,.12); --info-bg:rgba(68,147,248,.14);
14
14
  }
15
15
  }
16
16
  :root[data-theme="dark"] {
17
17
  --bg:#0d1117; --panel:#161b22; --panel2:#0d1117; --edge:#30363d; --rule:#2b323a; --fg:#e6edf3; --muted:#9198a1;
18
18
  --accent:#4493f8; --accent-solid:#1f6feb; --ok:#3fb950; --warn:#d29922; --crit:#f85149; --glow:rgba(68,147,248,.35);
19
- --up:#6fcbe6; --down:#d0a0ee; --shadow:0 1px 0 rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.45); --grid:rgba(255,255,255,.04);
19
+ --up:#6fcbe6; --down:#d0a0ee; --shadow:0 1px 0 rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.45); --grid:rgba(255,255,255,.04); --dot:rgba(255,255,255,.16);
20
20
  --warn-bg:rgba(210,153,34,.14); --ok-bg:rgba(63,185,80,.12); --crit-bg:rgba(248,81,73,.12); --info-bg:rgba(68,147,248,.14);
21
21
  }
22
22
  * { box-sizing:border-box; }
@@ -58,7 +58,7 @@
58
58
  .workspace { display:block; height:max(540px, calc(100vh - 232px)); border:1px solid var(--edge); background:var(--panel); border-radius:12px; overflow:hidden; box-shadow:var(--shadow); }
59
59
  .canvaswrap { position:relative; display:flex; flex-direction:column; min-width:0; min-height:0; height:100%; }
60
60
  #viewport { position:relative; flex:1; min-height:0; overflow:hidden; cursor:grab; touch-action:none; user-select:none;
61
- background:radial-gradient(760px 380px at 4% 0%, var(--glow), transparent 65%), radial-gradient(640px 320px at 98% 100%, color-mix(in srgb, var(--ok) 16%, transparent), transparent 70%), linear-gradient(var(--grid) 1px, transparent 1px) 0 0/28px 28px, linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0/28px 28px, var(--bg); }
61
+ background:radial-gradient(760px 380px at 4% 0%, var(--glow), transparent 65%), radial-gradient(640px 320px at 98% 100%, color-mix(in srgb, var(--ok) 16%, transparent), transparent 70%), radial-gradient(circle, var(--dot) var(--dot-size), transparent calc(var(--dot-size) + .5px)) 0 0 / var(--dot-gap) var(--dot-gap), var(--bg); }
62
62
  #viewport.panning { cursor:grabbing; } #viewport.hand .node { cursor:grab; }
63
63
  #world { position:absolute; left:0; top:0; transform-origin:0 0; will-change:transform; }
64
64
  #viewport.anim #world, #viewport.anim .hd, #viewport.anim .ph { transition:transform .28s cubic-bezier(.2,.8,.2,1), left .28s cubic-bezier(.2,.8,.2,1), width .28s cubic-bezier(.2,.8,.2,1); }
@@ -70,15 +70,21 @@
70
70
  .bandlabel b { font-size:13px; } .bandlabel .bd { font-size:10.5px; font-weight:700; padding:0 6px; border:1px solid currentColor; color:var(--muted); letter-spacing:.03em; text-transform:uppercase; }
71
71
  .bandlabel .bd.t-ok { color:var(--ok); } .bandlabel .bd.t-warn { color:var(--warn); } .bandlabel .bn { font-size:11.5px; color:var(--muted); }
72
72
  .node { position:absolute; background:var(--panel); border:1px solid var(--edge); border-radius:8px; padding:5px 10px 7px; box-shadow:var(--shadow); transition:opacity .35s, transform .35s, box-shadow .2s, border-color .2s; cursor:pointer; z-index:2; }
73
+ .node.gateway { border:0; background:transparent; box-shadow:none; padding:0; border-radius:0; display:flex; align-items:center; justify-content:center; }
74
+ .node.gateway svg.gw { position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
75
+ .node.gateway polygon { stroke-width:2; vector-effect:non-scaling-stroke; }
76
+ .node.gateway .gw-title { position:relative; width:58%; text-align:center; font-size:11px; font-weight:600; line-height:1.2; color:var(--fg); overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow-wrap:anywhere; }
77
+ .node.gateway:hover, .node.gateway.lit, .node.gateway.sel { filter:drop-shadow(0 0 7px var(--accent)); }
73
78
  .node.wide { overflow:hidden; }
74
79
  .node:hover { border-color:var(--accent); box-shadow:0 0 0 3px var(--glow), var(--shadow); }
75
80
  .node .t { display:flex; gap:4px; align-items:flex-start; font-weight:600; line-height:1.25; font-size:13px; }
76
81
  .node .t .name { overflow-wrap:anywhere; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
82
+ .node .fold { flex:none; color:var(--accent); font-size:11px; }
77
83
  .node .s { color:var(--muted); font-size:12px; line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
78
84
  .ev { font-size:10.5px; font-weight:700; letter-spacing:.03em; }
79
85
  .node.wide .t { font-weight:500; } .node.wide .s { white-space:normal; }
80
- .node.ref { padding:4px 9px; border-style:dashed; box-shadow:none; background:color-mix(in srgb, var(--panel) 70%, transparent); } .node.ref .t { font-size:12px; } .node.ref .s { font-size:11px; }
81
- .node.sel { outline:2px solid var(--accent); outline-offset:2px; } .node.dim { opacity:.28; } .node.off { opacity:0; transform:translateY(8px); pointer-events:none; }
86
+ .node.ref { padding:4px 9px; border-style:dashed; box-shadow:none; background:color-mix(in srgb, var(--panel) 70%, transparent); } .node.ref .t { font-size:12px; } .node.ref .t .name { display:block; min-width:0; white-space:nowrap; text-overflow:ellipsis; } .node.ref .s { font-size:11px; }
87
+ .node.sel { outline:2px solid var(--accent); outline-offset:2px; } .node.dim { opacity:.28; } .node.off { opacity:0; visibility:hidden; transform:translateY(8px); pointer-events:none; }
82
88
  .node .bar { position:absolute; left:0; right:0; bottom:0; display:flex; height:4px; overflow:hidden; border-radius:0 0 7px 7px; background:var(--panel2); } .node .bar i { display:block; height:100%; } .bar .good { background:var(--ok); } .bar .neutral { background:var(--muted); } .bar .gap { background:var(--warn); }
83
89
  .newdot { display:none; width:7px; height:7px; border-radius:50%; background:var(--accent); margin:5px 4px 0 0; flex:none; } body.alt .node.isnew .newdot { display:inline-block; }
84
90
  body.alt .node.isnew.pulse { animation:newring 1.8s ease-out 1; }
@@ -86,8 +92,8 @@
86
92
  .cor.up { right:6px; background:var(--info-bg); color:var(--accent); } .cor.meas { right:6px; background:var(--ok-bg); color:var(--ok); } .cor.up + .cor.meas { right:27px; }
87
93
  .node.hascor .t { padding-right:24px; } .node.hascor2 .t { padding-right:44px; }
88
94
  #viewport.lod1 .node .s, #viewport.lod1 .bandlabel .bn { display:none; } #viewport.lod2 .node .cor, #viewport.lod2 .node.ref .s { display:none; }
89
- path.edge { fill:none; stroke-width:1.8; transition:opacity .35s; vector-effect:non-scaling-stroke; }
90
- path.edge.hot { stroke:var(--accent); stroke-width:2.4; opacity:1; stroke-dasharray:6 8; animation:flowhot .9s linear infinite; filter:drop-shadow(0 0 5px var(--accent)); }
95
+ path.edge { fill:none; stroke-width:var(--edge-w); transition:opacity .35s; vector-effect:non-scaling-stroke; }
96
+ path.edge.hot { stroke:var(--accent); stroke-width:var(--edge-w-hot); opacity:1; stroke-dasharray:6 8; animation:flowhot .9s linear infinite; filter:drop-shadow(0 0 3px var(--accent)); }
91
97
  path.edge.dim { opacity:.07; filter:none; } path.edge.off { opacity:0; }
92
98
  .elabel { position:absolute; font-size:11px; padding:0 6px; border-radius:9px; background:var(--panel); border:1px solid var(--edge); color:var(--muted); white-space:nowrap; transform:translate(-50%,-50%); opacity:0; transition:opacity .35s; z-index:4; } .elabel.show { opacity:1; } .elabel.off { display:none; }
93
99
  #cols { position:absolute; left:0; right:0; top:0; height:44px; pointer-events:none; z-index:20; background:linear-gradient(var(--bg) 62%, transparent); }
@@ -140,8 +146,8 @@
140
146
  .node.lit { border-color:var(--accent); box-shadow:0 0 0 2px var(--glow), 0 0 18px var(--glow), var(--shadow); }
141
147
  .node.sel { animation:selpulse 2.4s ease-out infinite; }
142
148
  .node.fail { border-color:var(--crit); background:var(--crit-bg); box-shadow:0 0 0 2px var(--crit-bg), 0 0 20px color-mix(in srgb, var(--crit) 45%, transparent); animation:failflash .9s ease-out 1; } .node.fail .s { color:var(--crit); font-weight:600; }
143
- path.trail { fill:none; stroke:var(--accent); vector-effect:none; stroke-width:calc(3.4px / var(--k, 1)); stroke-linecap:round; filter:drop-shadow(0 0 6px var(--accent)); opacity:.95; }
144
- path.ripple { fill:none; stroke:var(--crit); vector-effect:none; stroke-width:calc(3.6px / var(--k, 1)); stroke-linecap:round; filter:drop-shadow(0 0 7px var(--crit)); }
149
+ path.trail { fill:none; stroke:var(--accent); vector-effect:none; stroke-width:calc(var(--trail-w) / var(--k, 1)); stroke-linecap:round; filter:drop-shadow(0 0 4px var(--accent)); opacity:.95; }
150
+ path.ripple { fill:none; stroke:var(--crit); vector-effect:none; stroke-width:calc(var(--ripple-w) / var(--k, 1)); stroke-linecap:round; filter:drop-shadow(0 0 4px var(--crit)); }
145
151
  .intro .band { animation:fadein .6s both; } .intro .node { animation:rise .55s both; animation-delay:calc(var(--c, 0) * 60ms + 150ms); } .intro #edges { animation:fadein 1s .5s both; }
146
152
  .intro .lcell, .intro .tile { animation:rise .5s both; animation-delay:calc(var(--i, 0) * 55ms); }
147
153
  #viewport:focus-visible { outline-offset:-2px; }
@@ -155,3 +161,31 @@
155
161
  @keyframes beat { 0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--ok) 60%, transparent);} 70%,100%{box-shadow:0 0 0 9px transparent;} }
156
162
  @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation:none !important; transition:none !important; } path.edge.hot { stroke-dasharray:none; } }
157
163
  @media (max-width: 1100px) { .summary { grid-template-columns:1fr; } .workspace { height:auto; } .workspace .canvaswrap { height:75vh; } .insp { width:min(340px, 92%); } #drawer { width:100%; } .layerstrip { grid-template-columns:repeat(3,1fr) !important; } }
164
+ #banner:not([hidden]) { margin:0 14px 10px; padding:8px 12px; color:var(--crit); background:var(--crit-bg); border:1px solid var(--crit); font-size:12px; }
165
+ #playbar:not([hidden]) { display:flex; flex-wrap:wrap; align-items:center; gap:7px; padding:7px 12px; border-top:1px solid var(--rule); background:var(--panel); font-size:12px; }
166
+ #playbar select, #playbar button { font-size:11px; }
167
+ #pbScrub { flex:1 1 140px; min-width:90px; }
168
+ #pbCaption { flex:1 1 100%; color:var(--fg); }
169
+ #pbCounter { font:11px var(--mono); color:var(--fg); }
170
+ #pbCounter.warn { color:var(--warn); } #pbCounter.breach { color:var(--crit); font-weight:700; }
171
+ #pbChoices { display:flex; gap:5px; flex-wrap:wrap; } #pbChoices:empty { display:none; }
172
+ #pbChoices .suggested { border-color:var(--accent); box-shadow:inset 0 -2px 0 var(--accent); }
173
+ circle.token { fill:var(--accent); stroke:var(--panel); stroke-width:2; filter:drop-shadow(0 0 5px var(--accent)); pointer-events:none; }
174
+ path.edge.playing { stroke:var(--accent); stroke-width:var(--edge-w-play); filter:drop-shadow(0 0 4px var(--accent)); opacity:1; }
175
+ path.edge.visited { stroke:var(--accent); opacity:.7; }
176
+ .node.playing { outline:2px solid var(--accent); outline-offset:2px; }
177
+ /* The pulse runs only while the player really plays; a paused step keeps the plain outline. */
178
+ body.playing .node.playing { animation:selpulse 1.8s ease-out infinite; }
179
+ .node.visited::after { content:"✓"; position:absolute; right:3px; bottom:1px; color:var(--accent); font-size:11px; }
180
+ .node.updated { animation:newring 1.2s ease-out 1; }
181
+ .node.added { animation:rise 1.2s ease-out 1; }
182
+ .node .t .name { min-width:0; flex:1 1 auto; }
183
+ .node .metric-badge { flex:none; max-width:72px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; position:relative; padding-bottom:3px; text-align:right; font:11px var(--mono); color:var(--accent); }
184
+ .node .metric-badge i { display:block; height:2px; position:absolute; bottom:0; left:0; background:var(--accent); }
185
+ .node .s.has-spark { padding-right:60px; }
186
+ .node .spark { position:absolute; right:6px; bottom:4px; overflow:visible; }
187
+ .node.gateway .metric-badge { position:absolute; right:9px; top:18px; }
188
+ .node.gateway:has(.metric-badge) .gw-title, .node.gateway.has-metrics .gw-title { width:45%; margin-right:42px; }
189
+ .node .spark polyline, .metrics polyline { fill:none; stroke:var(--accent); stroke-width:1.5; }
190
+ .metrics svg { max-width:100%; margin-top:8px; } .metric-range { display:flex; justify-content:space-between; width:300px; max-width:100%; font:10px var(--mono); color:var(--muted); }
191
+ @media (forced-colors: active) { #viewport { background: Canvas; } }
@@ -1,6 +1,6 @@
1
1
  import { test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { relatives, connected } from "./trace.ts";
3
+ import { relatives, connected, withinHops } from "./trace.ts";
4
4
 
5
5
  const edges = [{ from: "a", to: "b" }, { from: "b", to: "c" }, { from: "x", to: "c" }, { from: "c", to: "d" }];
6
6
  const id = (s: string) => s;
@@ -17,4 +17,24 @@ test("a cycle terminates", () => {
17
17
  const cyc = [{ from: "a", to: "b" }, { from: "b", to: "a" }];
18
18
  assert.deepEqual([...relatives(cyc, id, "a", "down")].sort(), ["a", "b"]);
19
19
  });
20
+ test("a loop-back does not break relatives", () => {
21
+ const cycle = [{ from: "a", to: "b" }, { from: "b", to: "c" }, { from: "c", to: "a" }];
22
+ assert.deepEqual([...relatives(cycle, id, "a", "down")].sort(), ["a", "b", "c"]);
23
+ assert.deepEqual([...relatives(cycle, id, "c", "up")].sort(), ["a", "b", "c"]);
24
+ });
20
25
  test("an unknown start returns only itself", () => assert.deepEqual([...relatives(edges, id, "nope", "down")], ["nope"]));
26
+
27
+ test("withinHops includes starts and walks links in either direction", () => {
28
+ assert.deepEqual([...withinHops(edges, id, ["b"], 0)].sort(), ["b"]);
29
+ assert.deepEqual([...withinHops(edges, id, ["b"], 1)].sort(), ["a", "b", "c"]);
30
+ assert.deepEqual([...withinHops(edges, id, ["b"], 2)].sort(), ["a", "b", "c", "d", "x"]);
31
+ });
32
+ test("withinHops canonicalizes aliases and joins multiple starts", () => {
33
+ const canon = (s: string) => s === "b2" ? "b" : s;
34
+ assert.deepEqual([...withinHops(edges, canon, ["b2", "x"], 1)].sort(), ["a", "b", "c", "x"]);
35
+ });
36
+ test("withinHops terminates on cycles and treats a negative radius as zero", () => {
37
+ const cycle = [{ from: "a", to: "b" }, { from: "b", to: "a" }];
38
+ assert.deepEqual([...withinHops(cycle, id, ["a"], 9)].sort(), ["a", "b"]);
39
+ assert.deepEqual([...withinHops(cycle, id, ["a"], -1)], ["a"]);
40
+ });
@@ -20,3 +20,21 @@ export function relatives(edges: Edge[], canonOf: (id: string) => string, start:
20
20
  export function connected(edges: Edge[], canonOf: (id: string) => string, start: string): Set<string> {
21
21
  return new Set([...relatives(edges, canonOf, start, "up"), ...relatives(edges, canonOf, start, "down")]);
22
22
  }
23
+
24
+ /** Undirected breadth-first radius around one or more nodes. */
25
+ export function withinHops(edges: Edge[], canonOf: (id: string) => string, starts: string[], n: number): Set<string> {
26
+ const found = new Set(starts.map(canonOf));
27
+ const radius = Number.isFinite(n) ? Math.max(0, Math.floor(n)) : 0;
28
+ let frontier = [...found];
29
+ for (let hop = 0; hop < radius && frontier.length; hop++) {
30
+ const next: string[] = [];
31
+ const current = new Set(frontier);
32
+ for (const edge of edges) {
33
+ const a = canonOf(edge.from), b = canonOf(edge.to);
34
+ if (current.has(a) && !found.has(b)) { found.add(b); next.push(b); }
35
+ if (current.has(b) && !found.has(a)) { found.add(a); next.push(a); }
36
+ }
37
+ frontier = next;
38
+ }
39
+ return found;
40
+ }