@sleep2agi/agent-network-dashboard 0.4.6-preview.31 → 0.4.6-preview.310
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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +41 -41
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
- package/.next/static/chunks/01lmbsd37fybu.js +1 -0
- package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
- package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
- package/.next/static/chunks/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0o40uf-rn28q6.js +1 -0
- package/.next/static/chunks/0q3hr1~viwzkt.js +4 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/0~ks9b48lw8hx.css +2 -0
- package/.next/static/chunks/13lvf-h-j8bmc.js +1 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/ChatPopover.tsx +38 -2
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +126 -0
- package/app/components/TopoGraph.tsx +5927 -258
- package/app/components/utils.ts +8 -7
- package/app/globals.css +110 -5
- package/app/lib/time.ts +36 -0
- package/app/lib/vendorIdentity.ts +14 -3
- package/package.json +2 -2
- package/public/sleep2agi-logo.svg +11 -0
- package/public/vendors/claude.svg +11 -0
- package/public/vendors/minimax.svg +11 -0
- package/public/vendors/openai.svg +12 -0
- package/screenshots/r293-p0/after-full.png +0 -0
- package/screenshots/r293-p0/after-topo.png +0 -0
- package/screenshots/r293-p0/baseline-full.png +0 -0
- package/screenshots/r293-p0/baseline-topo.png +0 -0
- package/screenshots/r293-p0/logo-integrated-full.png +0 -0
- package/screenshots/r293-p0/logo-integrated-topo.png +0 -0
- package/scripts/help-overlay-topo-test.mjs +44 -0
- package/scripts/p0-topo-screenshot.mjs +82 -0
- package/scripts/topo-active-filter-pill-test.mjs +101 -0
- package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
- package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
- package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
- package/scripts/topo-active-links-chip-test.mjs +73 -0
- package/scripts/topo-active-links-empty-recede-test.mjs +125 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-active-pulse-ease-test.mjs +120 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-brand-watermark-test.mjs +97 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chat-target-ring-ease-test.mjs +82 -0
- package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
- package/scripts/topo-chip-empty-recede-test.mjs +116 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chip-row-semantic-gap-test.mjs +97 -0
- package/scripts/topo-chip-row-tabular-test.mjs +111 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-icon-stroke-test.mjs +95 -0
- package/scripts/topo-chrome-pop-extension-test.mjs +98 -0
- package/scripts/topo-chrome-pop-nodesize-test.mjs +88 -0
- package/scripts/topo-chrome-press-state-test.mjs +135 -0
- package/scripts/topo-chrome-strip-semantic-gap-test.mjs +99 -0
- package/scripts/topo-chrome-strip-theme-ease-test.mjs +99 -0
- package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
- package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
- package/scripts/topo-click-ripple-ease-test.mjs +94 -0
- package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
- package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
- package/scripts/topo-cmdk-pin-test.mjs +123 -0
- package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
- package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
- package/scripts/topo-corner-radius-unify-test.mjs +103 -0
- package/scripts/topo-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-dense-alias-fill-transition-test.mjs +133 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-crossfade-test.mjs +138 -0
- package/scripts/topo-edge-badge-hot-test.mjs +115 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -0
- package/scripts/topo-edge-badge-lift-test.mjs +150 -0
- package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
- package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
- package/scripts/topo-edge-badge-text-pin-test.mjs +121 -0
- package/scripts/topo-edge-badge-theme-ease-test.mjs +89 -0
- package/scripts/topo-edge-count-badge-test.mjs +86 -0
- package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
- package/scripts/topo-edge-fadein-test.mjs +106 -0
- package/scripts/topo-edge-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-ping-pulse-retired-test.mjs +119 -0
- package/scripts/topo-edge-stroke-ease-test.mjs +100 -0
- package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-empty-state-crossfade-test.mjs +130 -0
- package/scripts/topo-empty-state-recenter-test.mjs +107 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-endpoint-ring-thicken-test.mjs +112 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-fit-key-test.mjs +106 -0
- package/scripts/topo-freshness-chip-test.mjs +74 -0
- package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-freshness-conditional-render-test.mjs +92 -0
- package/scripts/topo-fullscreen-active-test.mjs +115 -0
- package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
- package/scripts/topo-group-count-test.mjs +6 -1
- package/scripts/topo-group-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-count-inherit-test.mjs +99 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -0
- package/scripts/topo-group-label-pin-spacing-test.mjs +136 -0
- package/scripts/topo-group-label-tint-test.mjs +99 -0
- package/scripts/topo-group-label-title-test.mjs +83 -0
- package/scripts/topo-group-pin-test.mjs +119 -0
- package/scripts/topo-group-pip-fadein-test.mjs +100 -0
- package/scripts/topo-group-pip-tabular-test.mjs +95 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-fadein-test.mjs +95 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-hubcore-ease-test.mjs +106 -0
- package/scripts/topo-groupbox-live-test.mjs +100 -0
- package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
- package/scripts/topo-groupbox-test.mjs +4 -2
- package/scripts/topo-help-overlay-r109-test.mjs +67 -0
- package/scripts/topo-help-overlay-r118-test.mjs +69 -0
- package/scripts/topo-help-overlay-r123-test.mjs +69 -0
- package/scripts/topo-help-overlay-r134-test.mjs +74 -0
- package/scripts/topo-help-overlay-r137-test.mjs +81 -0
- package/scripts/topo-help-overlay-r141-test.mjs +86 -0
- package/scripts/topo-help-overlay-r153-test.mjs +85 -0
- package/scripts/topo-help-overlay-r59-test.mjs +67 -0
- package/scripts/topo-help-overlay-r65-test.mjs +64 -0
- package/scripts/topo-help-overlay-r70-test.mjs +63 -0
- package/scripts/topo-help-overlay-r78-test.mjs +59 -0
- package/scripts/topo-help-overlay-r81-test.mjs +58 -0
- package/scripts/topo-help-overlay-r87-test.mjs +64 -0
- package/scripts/topo-help-overlay-r91-test.mjs +65 -0
- package/scripts/topo-hot-tail-crossfade-test.mjs +117 -0
- package/scripts/topo-html-overlay-padding-unify-test.mjs +120 -0
- package/scripts/topo-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-center-crossfade-test.mjs +124 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-digit-scale-test.mjs +129 -0
- package/scripts/topo-hub-fadein-test.mjs +88 -0
- package/scripts/topo-hub-hover-lift-test.mjs +101 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -0
- package/scripts/topo-hub-pip-theme-ease-test.mjs +116 -0
- package/scripts/topo-hub-spoke-ease-test.mjs +120 -0
- package/scripts/topo-hub-title-test.mjs +93 -0
- package/scripts/topo-hub-working-count-test.mjs +99 -0
- package/scripts/topo-ingroup-edge-test.mjs +103 -0
- package/scripts/topo-inner-radar-ring-retired-test.mjs +89 -0
- package/scripts/topo-kicker-color-test.mjs +93 -0
- package/scripts/topo-kicker-tracking-test.mjs +101 -0
- package/scripts/topo-label-card-theme-ease-test.mjs +85 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-hover-text-preview-test.mjs +101 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-border-unify-test.mjs +104 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-legend-compress-test.mjs +107 -0
- package/scripts/topo-legend-count-empty-test.mjs +126 -0
- package/scripts/topo-legend-count-tabular-parity-test.mjs +90 -0
- package/scripts/topo-legend-count-tabular-test.mjs +87 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-count-tier-fill-test.mjs +121 -0
- package/scripts/topo-legend-header-symmetric-inset-test.mjs +112 -0
- package/scripts/topo-legend-hitbox-swatch-center-test.mjs +93 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-offline-delimiter-test.mjs +84 -0
- package/scripts/topo-legend-panel-header-test.mjs +83 -0
- package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
- package/scripts/topo-legend-pin-test.mjs +128 -0
- package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
- package/scripts/topo-legend-row-pin-spacing-test.mjs +124 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
- package/scripts/topo-legend-swatch-radius-test.mjs +78 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
- package/scripts/topo-minimap-rect-stroke-test.mjs +94 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-monogram-font-test.mjs +112 -0
- package/scripts/topo-monogram-stroke-test.mjs +101 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-label-card-stroke-test.mjs +135 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-text-fill-transition-test.mjs +119 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-particles-retired-test.mjs +91 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-fadein-test.mjs +102 -0
- package/scripts/topo-panel-hot-tail-fade-test.mjs +132 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-panel-theme-ease-test.mjs +85 -0
- package/scripts/topo-panel-title-fill-ease-test.mjs +91 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-color-ease-test.mjs +111 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-tabular-test.mjs +96 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-intersection-warning-crossfade-test.mjs +107 -0
- package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-popover-meta-test.mjs +78 -0
- package/scripts/topo-prepublish-guard-test.mjs +95 -0
- package/scripts/topo-pressure-bar-test.mjs +69 -0
- package/scripts/topo-pressure-hover-test.mjs +123 -0
- package/scripts/topo-pressure-pin-test.mjs +119 -0
- package/scripts/topo-pressure-seg-self-hover-test.mjs +126 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
- package/scripts/topo-pulse-dot-crossfade-test.mjs +122 -0
- package/scripts/topo-pulse-dot-retired-test.mjs +86 -0
- package/scripts/topo-pulse-rate-test.mjs +71 -0
- package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -0
- package/scripts/topo-recent-panel-footer-breath-test.mjs +142 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-more-crossfade-test.mjs +124 -0
- package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
- package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
- package/scripts/topo-recent-panel-more-test.mjs +106 -0
- package/scripts/topo-recent-panel-readability-bump-test.mjs +151 -0
- package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-fadein-test.mjs +107 -0
- package/scripts/topo-recent-row-freshness-test.mjs +102 -0
- package/scripts/topo-recent-row-hot-test.mjs +110 -0
- package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
- package/scripts/topo-recent-row-hover-test.mjs +122 -0
- package/scripts/topo-recent-row-pin-spacing-test.mjs +137 -0
- package/scripts/topo-recent-row-pin-test.mjs +126 -0
- package/scripts/topo-recent-row-tint-test.mjs +91 -0
- package/scripts/topo-recent-row-title-test.mjs +112 -0
- package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
- package/scripts/topo-recent-row-ts-test.mjs +95 -0
- package/scripts/topo-recent-row-typography-test.mjs +119 -0
- package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
- package/scripts/topo-recent-signal-empty-test.mjs +63 -0
- package/scripts/topo-reduced-motion-test.mjs +77 -0
- package/scripts/topo-reset-spin-test.mjs +120 -0
- package/scripts/topo-runtime-badge-grow-test.mjs +114 -0
- package/scripts/topo-spokes-retired-test.mjs +93 -0
- package/scripts/topo-starfield-density-test.mjs +89 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -0
- package/scripts/topo-tabular-nums-sweep-test.mjs +93 -0
- package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
- package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
- package/scripts/topo-tier-ring-test.mjs +69 -0
- package/scripts/topo-tier-ring-tint-test.mjs +110 -0
- package/scripts/topo-tier-stagger-test.mjs +89 -0
- package/scripts/topo-title-block-tight-leading-test.mjs +95 -0
- package/scripts/topo-title-tracking-test.mjs +98 -0
- package/scripts/topo-toggle-inactive-cyan-hover-test.mjs +110 -0
- package/scripts/topo-top-rail-theme-ease-test.mjs +89 -0
- package/scripts/topo-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-chip-self-hover-test.mjs +131 -0
- package/scripts/topo-vendor-chip-tabular-test.mjs +92 -0
- package/scripts/topo-vendor-chip-threshold-test.mjs +78 -0
- package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
- package/scripts/topo-vendor-pill-test.mjs +125 -0
- package/scripts/topo-vendor-pin-test.mjs +125 -0
- package/scripts/topo-view-smooth-test.mjs +131 -0
- package/scripts/topo-watermark-tracking-test.mjs +99 -0
- package/scripts/topo-working-chip-pin-test.mjs +154 -0
- package/scripts/topo-working-halo-breath-retired-test.mjs +99 -0
- package/scripts/topo-wrapper-flow-arrow-theme-test.mjs +97 -0
- package/scripts/topo-wrapper-shadow-theme-ease-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/01u5zo8b7r_r3.js +0 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqit.b4j_6rz.js +0 -1
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0pl7l_.2im.j0.js +0 -7
- package/.next/static/chunks/0qcfcgdthhos6.js +0 -1
- package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
- package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
- package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
- package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_buildManifest.js +0 -0
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{mgs4E0Fu2JlZsA5DB0XUu → Kkkh4U0z1GCAKfQMsfmjt}/_ssgManifest.js +0 -0
package/app/components/utils.ts
CHANGED
|
@@ -11,14 +11,15 @@ export function previewContent(raw: string | null | undefined): string {
|
|
|
11
11
|
.trim() || '--';
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// Round 44 / Loop: timeAgo now delegates to the shared lib/time helper.
|
|
15
|
+
// The old in-line `replace + 'Z'` parse appended a Z to already-ISO
|
|
16
|
+
// inputs (producing "…ZZ", browser-fragile) — strict-superset semantics
|
|
17
|
+
// preserved for SQL-style inputs, fixed for ISO. Plus a 'just now' fallback
|
|
18
|
+
// when clock skew puts the timestamp in the future. Five callers benefit:
|
|
19
|
+
// /admin · /logs · /settings/networks · InboxPanel · /messages.
|
|
20
|
+
import { relativeAgo } from '../lib/time';
|
|
14
21
|
export function timeAgo(dateStr: string): string {
|
|
15
|
-
|
|
16
|
-
const diff = Date.now() - new Date(dateStr.replace(' ', 'T') + 'Z').getTime();
|
|
17
|
-
const s = Math.floor(diff / 1000);
|
|
18
|
-
if (s < 60) return `${s}s ago`;
|
|
19
|
-
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
|
|
20
|
-
if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
|
|
21
|
-
return `${Math.floor(s / 86400)}d ago`;
|
|
22
|
+
return relativeAgo(dateStr) ?? '--';
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function statusColor(status: string, hasSse: boolean): string {
|
package/app/globals.css
CHANGED
|
@@ -828,6 +828,41 @@ body {
|
|
|
828
828
|
}
|
|
829
829
|
.anet-fade-in { animation: anet-fade-in 0.15s ease-out; }
|
|
830
830
|
|
|
831
|
+
/* Round 184 — chrome reset button click-spin. The reset button's
|
|
832
|
+
onClick triggers R168 smoothView crossfade on the canvas, but the
|
|
833
|
+
BUTTON itself had no visual feedback that the click registered. A
|
|
834
|
+
single 360° rotation on the refresh-arrow icon (450ms ease-out) is
|
|
835
|
+
a quick "yes, I heard you" confirmation. Counter-clockwise (-360°)
|
|
836
|
+
reads as "rewind" / "undo" — natural for a reset gesture. Mirror
|
|
837
|
+
to R52's hub click ripple at the chrome scope. */
|
|
838
|
+
@keyframes anet-reset-spin {
|
|
839
|
+
from { transform: rotate(0deg); }
|
|
840
|
+
to { transform: rotate(-360deg); }
|
|
841
|
+
}
|
|
842
|
+
.anet-reset-spin {
|
|
843
|
+
animation: anet-reset-spin 0.45s cubic-bezier(0.4, 0, 0.2, 1);
|
|
844
|
+
transform-origin: center;
|
|
845
|
+
transform-box: fill-box;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/* Round 186 — chrome zoom-in / zoom-out buttons get a brief icon pop
|
|
849
|
+
on click. Same click-feel idiom R184 added for the reset button —
|
|
850
|
+
the canvas already smoothes via R168/R169 smoothView, but the
|
|
851
|
+
chrome BUTTON itself needs its own confirmation. A quick scale
|
|
852
|
+
up-then-back (1 → 1.18 → 1 over 220ms) reads as "tapped". Same
|
|
853
|
+
transform-box: fill-box anchoring as R184 keeps the icon
|
|
854
|
+
centered in place. */
|
|
855
|
+
@keyframes anet-chrome-pop {
|
|
856
|
+
0% { transform: scale(1); }
|
|
857
|
+
50% { transform: scale(1.18); }
|
|
858
|
+
100% { transform: scale(1); }
|
|
859
|
+
}
|
|
860
|
+
.anet-chrome-pop {
|
|
861
|
+
animation: anet-chrome-pop 0.22s ease-out;
|
|
862
|
+
transform-origin: center;
|
|
863
|
+
transform-box: fill-box;
|
|
864
|
+
}
|
|
865
|
+
|
|
831
866
|
/* Round 36 — current-step ring pulse on TaskDrawer timeline. Halo gently
|
|
832
867
|
breathes around the active step's dot so users can spot "task is here". */
|
|
833
868
|
@keyframes anet-current-step-pulse-kf {
|
|
@@ -840,24 +875,93 @@ body {
|
|
|
840
875
|
|
|
841
876
|
/* Round 45 — TopoGraph rotating radar sweep wedge. 6s slow rotation
|
|
842
877
|
gives the topology canvas a real "radar scan" feel without distracting
|
|
843
|
-
from the agent nodes.
|
|
878
|
+
from the agent nodes.
|
|
879
|
+
R146: split shorthand into longhand so per-render inline style can
|
|
880
|
+
override animation-duration via --sweep-dur, joining the R145
|
|
881
|
+
--spoke-dur / R132 --march-dur pattern. Default 6s preserves R45's
|
|
882
|
+
original cadence for any caller that forgets the var. */
|
|
844
883
|
@keyframes anet-topo-sweep-kf {
|
|
845
884
|
0% { transform: rotate(0deg); }
|
|
846
885
|
100% { transform: rotate(360deg); }
|
|
847
886
|
}
|
|
848
887
|
.anet-topo-sweep {
|
|
849
|
-
animation: anet-topo-sweep-kf
|
|
888
|
+
animation-name: anet-topo-sweep-kf;
|
|
889
|
+
animation-duration: var(--sweep-dur, 6s);
|
|
890
|
+
animation-timing-function: linear;
|
|
891
|
+
animation-iteration-count: infinite;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/* R155 — focus-visible outline for TopoGraph chip-row interactives.
|
|
895
|
+
Cyber theme's dark canvas often swallows the browser default focus
|
|
896
|
+
ring; R154 fixed it for chrome buttons via Tailwind's focus-visible:
|
|
897
|
+
ring (box-shadow). Chip-row chips reuse `box-shadow` for the R88 /
|
|
898
|
+
R139 / R140 pin-mirror inset — so a focus box-shadow would conflict
|
|
899
|
+
with the pinned-state shadow. `outline` is a separate CSS property
|
|
900
|
+
and doesn't fight box-shadow, so we use it here. `currentColor`
|
|
901
|
+
inherits the chip's own accent (green for working, cyan for online,
|
|
902
|
+
per-vendor for letters, etc.). Only fires on :focus-visible
|
|
903
|
+
(keyboard) — mouse focus stays unstyled. */
|
|
904
|
+
.anet-topo-chip-focus:focus-visible {
|
|
905
|
+
outline: 2px solid currentColor;
|
|
906
|
+
outline-offset: 1px;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* R156 — focus-visible outline for SVG-side TopoGraph interactives.
|
|
910
|
+
Same idiom as R155's chip-row class but for SVG <g> elements
|
|
911
|
+
(recent-signal rows, legend rows, group labels, edge badges,
|
|
912
|
+
node bodies, "+N more" footer). Each <g> already has role=
|
|
913
|
+
"button"/"link" + tabIndex=0 + onKeyDown (R116/R121/R133/R143/
|
|
914
|
+
R144/R151/R152). Browser default focus outline on SVG is hard
|
|
915
|
+
to spot against the canvas; explicit cyan-300 ring matches the
|
|
916
|
+
dashboard's legendAccent. 2-px outline-offset gives breathing
|
|
917
|
+
room around the painted bounding box. */
|
|
918
|
+
.anet-topo-svg-focus:focus-visible {
|
|
919
|
+
outline: 2px solid #67e8f9;
|
|
920
|
+
outline-offset: 2px;
|
|
850
921
|
}
|
|
851
922
|
|
|
852
923
|
/* Round 46 — animated dashed spokes flowing from hub outward. Each spoke
|
|
853
924
|
gets a small animationDelay (set inline) so the dashes don't all flow
|
|
854
|
-
in sync — reads as "command relay" pulse rather than a metronome.
|
|
925
|
+
in sync — reads as "command relay" pulse rather than a metronome.
|
|
926
|
+
R145: split shorthand into longhand so per-render inline style can
|
|
927
|
+
override animation-duration via the --spoke-dur custom property —
|
|
928
|
+
same idiom R132 uses for --march-dur on group boxes. Default 2.4s
|
|
929
|
+
when --spoke-dur isn't set, so any future caller that forgets the
|
|
930
|
+
var keeps R46's original cadence. */
|
|
855
931
|
@keyframes anet-topo-spoke-flow-kf {
|
|
856
932
|
from { stroke-dashoffset: 0; }
|
|
857
933
|
to { stroke-dashoffset: -40; }
|
|
858
934
|
}
|
|
859
935
|
.anet-topo-spoke-flow {
|
|
860
|
-
animation: anet-topo-spoke-flow-kf
|
|
936
|
+
animation-name: anet-topo-spoke-flow-kf;
|
|
937
|
+
animation-duration: var(--spoke-dur, 2.4s);
|
|
938
|
+
animation-timing-function: linear;
|
|
939
|
+
animation-iteration-count: infinite;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/* Round 85 — group-box "marching ants" perimeter drift.
|
|
943
|
+
Applied to a grid-layout group box whose `statuses.working > 0`
|
|
944
|
+
AND that is neither hovered nor pinned (those treatments already
|
|
945
|
+
carry their own visual emphasis via solid stroke). Slow 12s
|
|
946
|
+
linear cycle reads as ambient motion, not animation — the eye
|
|
947
|
+
parses "this group has live work" without registering the box
|
|
948
|
+
as moving. R86 stride matches the box's `strokeDasharray="6 6"`
|
|
949
|
+
so a single full cycle returns to a frame-identical state.
|
|
950
|
+
prefers-reduced-motion handled by the blanket override below.
|
|
951
|
+
R132: split shorthand into longhand so per-group inline style can
|
|
952
|
+
override animation-duration via the --march-dur custom property
|
|
953
|
+
without re-declaring keyframe + timing + iteration count. Default
|
|
954
|
+
stays at 12s when --march-dur isn't set, so existing single-group
|
|
955
|
+
call sites keep their cadence. */
|
|
956
|
+
@keyframes anet-topo-groupbox-march-kf {
|
|
957
|
+
from { stroke-dashoffset: 0; }
|
|
958
|
+
to { stroke-dashoffset: -12; }
|
|
959
|
+
}
|
|
960
|
+
.anet-topo-groupbox-live {
|
|
961
|
+
animation-name: anet-topo-groupbox-march-kf;
|
|
962
|
+
animation-duration: var(--march-dur, 12s);
|
|
963
|
+
animation-timing-function: linear;
|
|
964
|
+
animation-iteration-count: infinite;
|
|
861
965
|
}
|
|
862
966
|
|
|
863
967
|
/* ─────────────────────────────────────────────────────────────────────
|
|
@@ -894,7 +998,8 @@ body {
|
|
|
894
998
|
.anet-fade-in,
|
|
895
999
|
.anet-current-step-pulse,
|
|
896
1000
|
.anet-topo-sweep,
|
|
897
|
-
.anet-topo-spoke-flow
|
|
1001
|
+
.anet-topo-spoke-flow,
|
|
1002
|
+
.anet-topo-groupbox-live {
|
|
898
1003
|
animation: none !important;
|
|
899
1004
|
}
|
|
900
1005
|
/* Tasks row grid 0fr↔1fr keep working (it's the toggle mechanism),
|
package/app/lib/time.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Shared timestamp helpers for hub-sourced data.
|
|
2
|
+
*
|
|
3
|
+
* Background — the CommHub serialises timestamps SQL-style without a
|
|
4
|
+
* zone ("2026-05-15 06:00:28"), but some test data uses full ISO
|
|
5
|
+
* ("…T06:00:28Z"). `Date.parse` on bare SQL is **local-time** in every
|
|
6
|
+
* browser the dashboard supports, so a UTC+8 operator silently sees
|
|
7
|
+
* every timestamp 8 h older than reality (Round 35 dug this out via
|
|
8
|
+
* the `isGhost` filter mis-fire).
|
|
9
|
+
*
|
|
10
|
+
* Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover
|
|
11
|
+
* (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;
|
|
12
|
+
* one source of truth here. */
|
|
13
|
+
|
|
14
|
+
/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings
|
|
15
|
+
* as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.
|
|
16
|
+
* Returns null for empty / unparseable input. */
|
|
17
|
+
export function parseHubTime(dateStr: string | null | undefined): number | null {
|
|
18
|
+
if (!dateStr) return null;
|
|
19
|
+
const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';
|
|
20
|
+
const t = Date.parse(iso);
|
|
21
|
+
return Number.isFinite(t) ? t : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Format `dateStr` as a short relative-time string ("6m ago" / "2h ago").
|
|
25
|
+
* Future timestamps (clock skew) collapse to "just now". Returns null when
|
|
26
|
+
* the input doesn't parse — callers can decide on a fallback. */
|
|
27
|
+
export function relativeAgo(dateStr: string | null | undefined): string | null {
|
|
28
|
+
const t = parseHubTime(dateStr);
|
|
29
|
+
if (t === null) return null;
|
|
30
|
+
const s = Math.floor((Date.now() - t) / 1000);
|
|
31
|
+
if (s < 0) return 'just now';
|
|
32
|
+
if (s < 60) return `${s}s ago`;
|
|
33
|
+
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
|
|
34
|
+
if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
|
|
35
|
+
return `${Math.floor(s / 86400)}d ago`;
|
|
36
|
+
}
|
|
@@ -54,7 +54,10 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
|
|
|
54
54
|
label: 'MiniMax',
|
|
55
55
|
mono: { bg: 'hsl(18 50% 26%)', ring: 'hsl(18 65% 52%)', text: 'hsl(20 80% 82%)' },
|
|
56
56
|
initial: 'M',
|
|
57
|
-
|
|
57
|
+
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
58
|
+
// the MiniMax trademark; geometric min/max zigzag in their warm-
|
|
59
|
+
// red palette. Replaces plain-letter "M" fallback.
|
|
60
|
+
logo: '/vendors/minimax.svg',
|
|
58
61
|
},
|
|
59
62
|
},
|
|
60
63
|
{
|
|
@@ -64,7 +67,11 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
|
|
|
64
67
|
label: 'Anthropic',
|
|
65
68
|
mono: { bg: 'hsl(16 32% 26%)', ring: 'hsl(16 48% 54%)', text: 'hsl(18 60% 84%)' },
|
|
66
69
|
initial: 'A',
|
|
67
|
-
|
|
70
|
+
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
71
|
+
// the Anthropic trademark; 4-pointed sparkle in their warm-orange
|
|
72
|
+
// palette evokes AI/Claude without imitating the official mark.
|
|
73
|
+
// Real Anthropic logo still pending Vincent-direct asset OK.
|
|
74
|
+
logo: '/vendors/claude.svg',
|
|
68
75
|
},
|
|
69
76
|
},
|
|
70
77
|
{
|
|
@@ -74,7 +81,11 @@ const VENDOR_RULES: Array<{ test: (m: string) => boolean; vendor: VendorIdentity
|
|
|
74
81
|
label: 'OpenAI',
|
|
75
82
|
mono: { bg: 'hsl(165 26% 22%)', ring: 'hsl(165 40% 44%)', text: 'hsl(165 45% 80%)' },
|
|
76
83
|
initial: 'O',
|
|
77
|
-
|
|
84
|
+
// P0 (Vincent 5222) custom-designed vendor badge — NOT a copy of
|
|
85
|
+
// the OpenAI trademark; hexagonal frame + center dot in their
|
|
86
|
+
// teal palette evokes geometric AI lattice without imitating the
|
|
87
|
+
// knot. Real OpenAI logo still pending Vincent-direct asset OK.
|
|
88
|
+
logo: '/vendors/openai.svg',
|
|
78
89
|
},
|
|
79
90
|
},
|
|
80
91
|
];
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/agent-network-dashboard",
|
|
3
|
-
"version": "0.4.6-preview.
|
|
3
|
+
"version": "0.4.6-preview.310",
|
|
4
4
|
"description": "Agent Network Dashboard — Web UI for managing AI Agent networks",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "next dev",
|
|
7
7
|
"build": "next build",
|
|
8
8
|
"start": "next start",
|
|
9
9
|
"lint": "eslint",
|
|
10
|
-
"prepublishOnly": "
|
|
10
|
+
"prepublishOnly": "[ -f .next/BUILD_ID ] || (echo 'prepublishOnly: .next/BUILD_ID missing — run npm run build first (see commit 05c1ebf body for R224 chunk-500 root cause)' >&2 && exit 1)"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
13
|
"agent-network-dashboard": "./bin/start.js"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
2
|
+
<!-- sleep2agi brand mark: a crescent moon — the "sleep" metaphor in the
|
|
3
|
+
name. Two-shape construction: outer disc minus offset inner disc =
|
|
4
|
+
crescent. uses currentColor so the embedding context can theme it. -->
|
|
5
|
+
<mask id="s2a-moon-mask">
|
|
6
|
+
<rect width="32" height="32" fill="black" />
|
|
7
|
+
<circle cx="16" cy="16" r="13" fill="white" />
|
|
8
|
+
<circle cx="20.5" cy="14.5" r="11" fill="black" />
|
|
9
|
+
</mask>
|
|
10
|
+
<rect width="32" height="32" fill="currentColor" mask="url(#s2a-moon-mask)" />
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<!-- Anthropic / Claude vendor mark.
|
|
3
|
+
NOT a copy of the Anthropic trademark — custom designed badge
|
|
4
|
+
in warm-orange palette. 4-rayed sparkle = "AI spark of insight".
|
|
5
|
+
Real Anthropic logo asset still gated on Vincent-direct. -->
|
|
6
|
+
<circle cx="32" cy="32" r="32" fill="hsl(16 32% 22%)" />
|
|
7
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(16 48% 54%)" stroke-width="2" />
|
|
8
|
+
<g fill="hsl(20 80% 78%)" transform="translate(32 32)">
|
|
9
|
+
<path d="M 0 -18 L 4 -4 L 18 0 L 4 4 L 0 18 L -4 4 L -18 0 L -4 -4 Z" />
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<!-- MiniMax vendor mark. NOT a copy of the MiniMax trademark —
|
|
3
|
+
custom designed badge: angular min/max zigzag in warm-red
|
|
4
|
+
palette evokes the function-shape without imitating the official
|
|
5
|
+
mark. Real MiniMax logo asset still gated on Vincent-direct. -->
|
|
6
|
+
<circle cx="32" cy="32" r="32" fill="hsl(18 50% 22%)" />
|
|
7
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(18 65% 52%)" stroke-width="2" />
|
|
8
|
+
<polyline points="14,42 22,22 32,42 42,22 50,42"
|
|
9
|
+
fill="none" stroke="hsl(20 80% 80%)" stroke-width="4"
|
|
10
|
+
stroke-linecap="round" stroke-linejoin="round" />
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<!-- OpenAI / GPT / Codex vendor mark. NOT a copy of the OpenAI
|
|
3
|
+
trademark — custom designed badge: hexagonal frame + center dot
|
|
4
|
+
in teal palette evokes "geometric AI lattice" without imitating
|
|
5
|
+
the OpenAI knot. Real OpenAI logo asset still gated on Vincent-
|
|
6
|
+
direct. -->
|
|
7
|
+
<circle cx="32" cy="32" r="32" fill="hsl(165 26% 20%)" />
|
|
8
|
+
<circle cx="32" cy="32" r="30" fill="none" stroke="hsl(165 40% 44%)" stroke-width="2" />
|
|
9
|
+
<polygon points="32,12 47,21 47,43 32,52 17,43 17,21"
|
|
10
|
+
fill="none" stroke="hsl(165 50% 78%)" stroke-width="3" stroke-linejoin="round" />
|
|
11
|
+
<circle cx="32" cy="32" r="4" fill="hsl(165 50% 78%)" />
|
|
12
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Round 25 verification: pressing `?` opens the help overlay, and the
|
|
2
|
+
* new "Topology canvas" section is present with the documented keys. */
|
|
3
|
+
import { chromium } from 'playwright';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
7
|
+
const browser = await chromium.launch({ headless: true });
|
|
8
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
|
9
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
10
|
+
await ctx.addInitScript(() => {
|
|
11
|
+
try { sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
12
|
+
});
|
|
13
|
+
await ctx.route('**/api/hub/status*', (route) => route.fulfill({ json: { sessions: [] } }));
|
|
14
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
15
|
+
const page = await ctx.newPage();
|
|
16
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
17
|
+
await page.waitForTimeout(400);
|
|
18
|
+
|
|
19
|
+
await page.keyboard.press('?');
|
|
20
|
+
await page.waitForTimeout(200);
|
|
21
|
+
|
|
22
|
+
// The overlay contains group headings; find the Topology canvas group + its rows.
|
|
23
|
+
const data = await page.evaluate(() => {
|
|
24
|
+
// The group heading is a <div>; its parent wraps heading + the <ul> of items.
|
|
25
|
+
const heading = [...document.querySelectorAll('[role="dialog"] div')].find(el => el.textContent === 'Topology canvas');
|
|
26
|
+
if (!heading) return null;
|
|
27
|
+
return {
|
|
28
|
+
headingPresent: true,
|
|
29
|
+
sectionText: (heading.parentElement?.textContent || '').replace(/\s+/g, ' ').trim(),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await browser.close();
|
|
34
|
+
const results = {
|
|
35
|
+
overlayOpened: !!data,
|
|
36
|
+
topologySectionPresent: !!data?.headingPresent,
|
|
37
|
+
hasZoomKeys: !!data && /Zoom in/.test(data.sectionText) && /Zoom out/.test(data.sectionText) && /Reset zoom/.test(data.sectionText),
|
|
38
|
+
hasMouseGestures: !!data && /wheel/.test(data.sectionText) && /Pan the canvas/.test(data.sectionText),
|
|
39
|
+
hasClickHint: !!data && /chat popover/.test(data.sectionText) && /dbl-click/.test(data.sectionText),
|
|
40
|
+
};
|
|
41
|
+
const ok = Object.values(results).every(Boolean);
|
|
42
|
+
console.log(`${ok ? '✅' : '❌'} help overlay topology section:`, JSON.stringify(results));
|
|
43
|
+
if (!ok && data) console.log('section text:', data.sectionText.slice(0, 300));
|
|
44
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* P0 (Vincent 5222) baseline + after screenshot of TopoGraph with a
|
|
2
|
+
* realistic 4-agent mixed-vendor fleet. Usage:
|
|
3
|
+
* node scripts/p0-topo-screenshot.mjs <out-prefix>
|
|
4
|
+
* Writes <out-prefix>-full.png (1600×900) and <out-prefix>-svg.png
|
|
5
|
+
* (just the SVG bbox, cropped). */
|
|
6
|
+
import { chromium } from 'playwright';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
|
|
9
|
+
const outPrefix = process.argv[2] || 'screenshots/r293-p0/baseline';
|
|
10
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
11
|
+
const browser = await chromium.launch({ headless: true });
|
|
12
|
+
const ctx = await browser.newContext({ viewport: { width: 1600, height: 1400 }, deviceScaleFactor: 2 });
|
|
13
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
14
|
+
await ctx.addInitScript(() => {
|
|
15
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
16
|
+
});
|
|
17
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
18
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
19
|
+
const r = await route.fetch();
|
|
20
|
+
const b = await r.json();
|
|
21
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
22
|
+
const mk = (alias, model, status = 'working') => ({
|
|
23
|
+
alias, status, model, runtime: 'claude-code-cli',
|
|
24
|
+
network_id: nid, project_dir: null,
|
|
25
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
26
|
+
});
|
|
27
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
28
|
+
mk('claude-1', 'claude-opus-4'),
|
|
29
|
+
mk('claude-2', 'claude-sonnet-4', 'idle'),
|
|
30
|
+
mk('codex-1', 'gpt-4o'),
|
|
31
|
+
mk('intern-1', 'internlm/internlm2'),
|
|
32
|
+
mk('minimax-1', 'minimax/abab6', 'idle'),
|
|
33
|
+
] } });
|
|
34
|
+
});
|
|
35
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [
|
|
36
|
+
{ from: 'claude-1', to: 'codex-1', text: 'review the diff please', ts: fresh },
|
|
37
|
+
{ from: 'codex-1', to: 'claude-1', text: 'lgtm, ship', ts: fresh },
|
|
38
|
+
{ from: 'intern-1', to: 'claude-1', text: 'logs uploaded', ts: fresh },
|
|
39
|
+
] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
|
|
42
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
44
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length >= 4, { timeout: 30000 });
|
|
45
|
+
await page.waitForTimeout(800);
|
|
46
|
+
|
|
47
|
+
// Scroll the topology card into view + measure.
|
|
48
|
+
const topoBox = await page.evaluate(() => {
|
|
49
|
+
const chromeEl = document.querySelector('[data-topo-chrome]');
|
|
50
|
+
if (!chromeEl) return null;
|
|
51
|
+
// Walk up to find the topology card container — has the SVG inside.
|
|
52
|
+
let card = chromeEl.parentElement;
|
|
53
|
+
while (card && !card.querySelector(':scope > svg')) card = card.parentElement;
|
|
54
|
+
if (!card) return null;
|
|
55
|
+
card.scrollIntoView({ block: 'start' });
|
|
56
|
+
// Allow scroll to settle.
|
|
57
|
+
return new Promise(resolve => {
|
|
58
|
+
requestAnimationFrame(() => {
|
|
59
|
+
const r = card.getBoundingClientRect();
|
|
60
|
+
resolve({ x: Math.max(0, r.x), y: Math.max(0, r.y), width: r.width, height: r.height });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
await page.waitForTimeout(400);
|
|
65
|
+
|
|
66
|
+
await page.screenshot({ path: `${outPrefix}-full.png`, fullPage: false });
|
|
67
|
+
if (topoBox && topoBox.width > 100 && topoBox.height > 100) {
|
|
68
|
+
// Re-measure after settling.
|
|
69
|
+
const box2 = await page.evaluate(() => {
|
|
70
|
+
const chromeEl = document.querySelector('[data-topo-chrome]');
|
|
71
|
+
let card = chromeEl?.parentElement;
|
|
72
|
+
while (card && !card.querySelector(':scope > svg')) card = card?.parentElement;
|
|
73
|
+
if (!card) return null;
|
|
74
|
+
const r = card.getBoundingClientRect();
|
|
75
|
+
return { x: Math.max(0, r.x), y: Math.max(0, r.y), width: r.width, height: r.height };
|
|
76
|
+
});
|
|
77
|
+
if (box2) {
|
|
78
|
+
await page.screenshot({ path: `${outPrefix}-topo.png`, clip: box2 });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
console.log(`✅ wrote ${outPrefix}-full.png + ${outPrefix}-topo.png`);
|
|
82
|
+
await browser.close();
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 64 verification: active-filter pills appear in chip row when
|
|
2
|
+
* pins are set and clear their pin on × click.
|
|
3
|
+
*
|
|
4
|
+
* - No pin → no pill rendered.
|
|
5
|
+
* - Pin status (via legend) → pill labelled "filter: working" with
|
|
6
|
+
* aria-label that includes "Clear working filter".
|
|
7
|
+
* - × button click → pin clears + node opacities restore.
|
|
8
|
+
* - Both pins independent: pin a status + pin a group → two pills.
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
} catch {}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const sessions = [
|
|
32
|
+
{ alias: 'alpha1', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
33
|
+
{ alias: 'alpha2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
34
|
+
{ alias: 'alpha3', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
35
|
+
{ alias: 'beta', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
];
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
44
|
+
await page.waitForTimeout(500);
|
|
45
|
+
|
|
46
|
+
const readPills = () => page.evaluate(() => {
|
|
47
|
+
return [...document.querySelectorAll('[data-active-filter]')].map(el => ({
|
|
48
|
+
kind: el.getAttribute('data-active-filter'),
|
|
49
|
+
text: (el.textContent || '').trim(),
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
const readWkrOpacity = () => page.evaluate(() => +(document.querySelector('g[data-node="alpha1"]')?.style.opacity || '1'));
|
|
53
|
+
|
|
54
|
+
const pillsBefore = await readPills();
|
|
55
|
+
|
|
56
|
+
// Pin working via legend.
|
|
57
|
+
await page.locator('g[data-legend-status="working"]').first().click({ force: true });
|
|
58
|
+
await page.mouse.move(10, 10);
|
|
59
|
+
await page.waitForTimeout(250);
|
|
60
|
+
const pillsAfterStatus = await readPills();
|
|
61
|
+
const wkrAfterStatus = await readWkrOpacity();
|
|
62
|
+
|
|
63
|
+
// Pin alpha group via label click.
|
|
64
|
+
await page.locator('g[data-group-label-hit="alpha"]').first().click({ force: true });
|
|
65
|
+
await page.mouse.move(10, 10);
|
|
66
|
+
await page.waitForTimeout(250);
|
|
67
|
+
const pillsBothPinned = await readPills();
|
|
68
|
+
|
|
69
|
+
// Click × on the status pill.
|
|
70
|
+
await page.locator('[data-active-filter="status"] button[aria-label*="working"]').first().click({ force: true });
|
|
71
|
+
await page.waitForTimeout(250);
|
|
72
|
+
const pillsAfterStatusClear = await readPills();
|
|
73
|
+
const wkrAfterStatusClear = await readWkrOpacity();
|
|
74
|
+
|
|
75
|
+
// Click × on the group pill.
|
|
76
|
+
await page.locator('[data-active-filter="group"] button[aria-label*="alpha"]').first().click({ force: true });
|
|
77
|
+
await page.waitForTimeout(250);
|
|
78
|
+
const pillsFinal = await readPills();
|
|
79
|
+
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const results = {
|
|
83
|
+
before_noPills: pillsBefore.length === 0,
|
|
84
|
+
statusPin_oneStatusPill: pillsAfterStatus.length === 1
|
|
85
|
+
&& pillsAfterStatus[0].kind === 'status'
|
|
86
|
+
&& /filter:\s*working/.test(pillsAfterStatus[0].text),
|
|
87
|
+
statusPin_dimsBeta: wkrAfterStatus >= 0.55, // alpha1 IS working — should stay
|
|
88
|
+
bothPinned_twoPills: pillsBothPinned.length === 2
|
|
89
|
+
&& pillsBothPinned.some(p => p.kind === 'status')
|
|
90
|
+
&& pillsBothPinned.some(p => p.kind === 'group'),
|
|
91
|
+
statusClear_only_group_remains: pillsAfterStatusClear.length === 1
|
|
92
|
+
&& pillsAfterStatusClear[0].kind === 'group',
|
|
93
|
+
statusClear_restoredOpacity: wkrAfterStatusClear >= 0.55,
|
|
94
|
+
groupClear_noPills: pillsFinal.length === 0,
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} active-filter pill:`, JSON.stringify(results),
|
|
98
|
+
`\n pillsAfterStatus=`, pillsAfterStatus,
|
|
99
|
+
`\n pillsBothPinned=`, pillsBothPinned,
|
|
100
|
+
`\n pillsAfterStatusClear=`, pillsAfterStatusClear);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|