@sleep2agi/agent-network-dashboard 0.5.1-preview.99 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +32 -32
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/server/app/_global-error.html +1 -1
  7. package/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +2 -2
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/admin.html +2 -2
  24. package/.next/server/app/admin.rsc +14 -14
  25. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  26. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  27. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  28. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  30. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  31. package/.next/server/app/index.html +2 -2
  32. package/.next/server/app/index.rsc +14 -14
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  34. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  35. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  36. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  37. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  38. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/login.html +2 -2
  40. package/.next/server/app/login.rsc +14 -14
  41. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  42. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  43. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  44. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  45. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  47. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/logs.html +2 -2
  49. package/.next/server/app/logs.rsc +14 -14
  50. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  51. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  56. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/messages.html +2 -2
  58. package/.next/server/app/messages.rsc +14 -14
  59. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  60. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  65. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/node.html +2 -2
  67. package/.next/server/app/node.rsc +14 -14
  68. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  69. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  70. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  71. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  72. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  73. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  74. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/nodes.html +2 -2
  76. package/.next/server/app/nodes.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  78. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  83. package/.next/server/app/page.js.nft.json +1 -1
  84. package/.next/server/app/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  86. package/.next/server/app/server-logs.html +2 -2
  87. package/.next/server/app/server-logs.rsc +14 -14
  88. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  89. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  90. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  91. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  92. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  93. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  94. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  95. package/.next/server/app/settings/networks.html +2 -2
  96. package/.next/server/app/settings/networks.rsc +14 -14
  97. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  98. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  99. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  100. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  101. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  102. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  103. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  104. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  106. package/.next/server/app/settings/tokens.html +2 -2
  107. package/.next/server/app/settings/tokens.rsc +14 -14
  108. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  109. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  110. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  111. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  112. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  113. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  114. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  115. package/.next/server/app/settings.html +2 -2
  116. package/.next/server/app/settings.rsc +14 -14
  117. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  118. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  119. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  120. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  121. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  122. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  123. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  125. package/.next/server/app/tasks.html +2 -2
  126. package/.next/server/app/tasks.rsc +14 -14
  127. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  128. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  129. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  130. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  131. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  132. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  133. package/.next/server/chunks/ssr/{[root-of-the-server]__03b.f76._.js → [root-of-the-server]__0sv~g.o._.js} +2 -2
  134. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -0
  135. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
  136. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  137. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  139. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  140. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  141. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  142. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  143. package/.next/server/middleware-build-manifest.js +3 -3
  144. package/.next/server/pages/404.html +2 -2
  145. package/.next/server/pages/500.html +1 -1
  146. package/.next/server/server-reference-manifest.js +1 -1
  147. package/.next/server/server-reference-manifest.json +1 -1
  148. package/.next/static/chunks/{0l_~q07bhpkcx.js → 03a4--7ncekmk.js} +1 -1
  149. package/.next/static/chunks/05admfiu6qfp2.js +1 -0
  150. package/.next/static/chunks/0a4hmfvj-81x5.css +2 -0
  151. package/.next/static/chunks/0d9mlqf.rjey5.js +1 -0
  152. package/.next/static/chunks/11puuje6at2jt.js +4 -0
  153. package/.next/static/chunks/{03~~oirxz7~vc.js → 15ub0_3b099x1.js} +1 -1
  154. package/.next/trace +2 -2
  155. package/.next/trace-build +1 -1
  156. package/app/components/ServersDrawer.tsx +17 -0
  157. package/app/components/TopoGraph.tsx +722 -76
  158. package/package.json +1 -1
  159. package/screenshots/v0.10.2-disk-verify/disk-render-full.png +0 -0
  160. package/screenshots/v0.10.2-disk-verify/disk-render.png +0 -0
  161. package/screenshots/v0.11.0-147/after.png +0 -0
  162. package/scripts/p0-147-screenshot.mjs +53 -0
  163. package/scripts/p0-servers-drawer-screenshot.mjs +2 -0
  164. package/scripts/topo-any-hover-attr-test.mjs +83 -0
  165. package/scripts/topo-any-pinned-attr-test.mjs +86 -0
  166. package/scripts/topo-chrome-fullscreen-icon-sw-test.mjs +92 -0
  167. package/scripts/topo-chrome-reset-icon-sw-test.mjs +80 -0
  168. package/scripts/topo-chrome-zoom-icon-sw-test.mjs +90 -0
  169. package/scripts/topo-dashboard-version-attr-test.mjs +69 -0
  170. package/scripts/topo-dense-alias-opacity-test.mjs +68 -0
  171. package/scripts/topo-edge-particle-hover-r-test.mjs +113 -0
  172. package/scripts/topo-endpoint-ring-r-hover-test.mjs +89 -0
  173. package/scripts/topo-group-box-geom-transition-test.mjs +110 -0
  174. package/scripts/topo-group-box-rx-pin-test.mjs +103 -0
  175. package/scripts/topo-group-label-count-fw-test.mjs +100 -0
  176. package/scripts/topo-group-label-fw-pin-test.mjs +99 -0
  177. package/scripts/topo-group-label-tint-geom-test.mjs +94 -0
  178. package/scripts/topo-group-label-tint-transition-test.mjs +97 -0
  179. package/scripts/topo-group-pip-fontsize-test.mjs +106 -0
  180. package/scripts/topo-group-tint-rx-pin-test.mjs +107 -0
  181. package/scripts/topo-hub-core-fill-hover-test.mjs +85 -0
  182. package/scripts/topo-hub-halo-r-hover-test.mjs +82 -0
  183. package/scripts/topo-legend-count-active-opacity-test.mjs +102 -0
  184. package/scripts/topo-legend-count-pin-fw-test.mjs +90 -0
  185. package/scripts/topo-minimap-viewport-opacity-test.mjs +96 -0
  186. package/scripts/topo-node-halo-hover-opacity-test.mjs +104 -0
  187. package/scripts/topo-node-halo-light-offline-test.mjs +80 -0
  188. package/scripts/topo-node-sub-text-fw-test.mjs +75 -0
  189. package/scripts/topo-overlap-stale-build-guard-test.mjs +66 -0
  190. package/scripts/topo-overlap-test.mjs +42 -1
  191. package/scripts/topo-recent-row-count-pin-fw-test.mjs +106 -0
  192. package/scripts/topo-recent-row-pip-hover-r-test.mjs +104 -0
  193. package/scripts/topo-runtime-icon-hover-test.mjs +96 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +0 -1
  195. package/.next/static/chunks/0.sf46gnv4wwm.js +0 -1
  196. package/.next/static/chunks/017hq2-5l~_98.css +0 -2
  197. package/.next/static/chunks/0_igeywsok2_-.js +0 -1
  198. package/.next/static/chunks/0igz0bww16uvc.js +0 -4
  199. /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → gowHgWkn_kpMCSBn8RFaa}/_buildManifest.js +0 -0
  200. /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → gowHgWkn_kpMCSBn8RFaa}/_clientMiddlewareManifest.js +0 -0
  201. /package/.next/static/{4rHxTzLwe2XC9M1rN-MpJ → gowHgWkn_kpMCSBn8RFaa}/_ssgManifest.js +0 -0
@@ -0,0 +1,106 @@
1
+ /* Round 445 verification: recent-row count tspan fontWeight lift on
2
+ * isRowPinned. Extends R320 cold/hot fw binary (600/700) to also fire
3
+ * on pin. cold+pinned → 700; cold+un-pinned → 600.
4
+ *
5
+ * Contract:
6
+ * - rest: every recent-row-count reports font-weight '600' +
7
+ * pinned='false'
8
+ * - click a recent-row: that row's count flips to '700' +
9
+ * pinned='true'; siblings stay rest
10
+ */
11
+ import { chromium } from 'playwright';
12
+ import { readFileSync } from 'node:fs';
13
+
14
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
15
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
16
+
17
+ const browser = await chromium.launch({ headless: true });
18
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
19
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
20
+ await ctx.addInitScript(() => {
21
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
22
+ });
23
+ await ctx.route('**/api/hub/status*', async (route) => {
24
+ const r = await route.fetch();
25
+ const b = await r.json();
26
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
27
+ const mk = (alias, status) => ({
28
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
29
+ network_id: nid, project_dir: null,
30
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
31
+ });
32
+ await route.fulfill({ response: r, json: { ...b, sessions: [
33
+ mk('alpha', 'working'),
34
+ mk('beta', 'idle'),
35
+ mk('gamma', 'idle'),
36
+ ] } });
37
+ });
38
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({
39
+ json: { messages: [
40
+ // Use only 1 message each so neither row crosses the hot threshold (≥10)
41
+ { id: 'm1', from_alias: 'alpha', to_alias: 'beta', content: 'ping', created_at: fresh, network_id: 'default' },
42
+ { id: 'm2', from_alias: 'alpha', to_alias: 'gamma', content: 'pong', created_at: fresh, network_id: 'default' },
43
+ ] },
44
+ }));
45
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
46
+
47
+ const page = await ctx.newPage();
48
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
49
+ await page.waitForSelector('[data-recent-row-count]', { timeout: 15000 });
50
+ await page.waitForTimeout(400);
51
+
52
+ const readAll = () => page.evaluate(() => {
53
+ const ts = [...document.querySelectorAll('[data-recent-row-count]')];
54
+ return ts.map(t => {
55
+ const row = t.closest('[data-recent-row]');
56
+ return {
57
+ rowKey: row?.getAttribute('data-recent-row') || null,
58
+ fw: t.getAttribute('font-weight'),
59
+ pinned: t.getAttribute('data-recent-row-count-pinned'),
60
+ hot: t.getAttribute('data-recent-row-count-hot'),
61
+ };
62
+ });
63
+ });
64
+
65
+ const rest = await readAll();
66
+ const firstRow = rest[0]?.rowKey;
67
+
68
+ // Pin the first row via click on its <g data-recent-row>
69
+ let pinned = null;
70
+ if (firstRow) {
71
+ const row = await page.$(`[data-recent-row="${firstRow}"]`);
72
+ if (row) {
73
+ await row.click();
74
+ await page.waitForTimeout(250);
75
+ pinned = await readAll();
76
+ }
77
+ }
78
+
79
+ const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
80
+ const sourceWired = /fontWeight=\{\(isHot \|\| isRowPinned\) \? '700' : '600'\}/.test(fileText);
81
+
82
+ await browser.close();
83
+
84
+ const restAll600 = rest.every(r => r.fw === '600');
85
+ const restNoPin = rest.every(r => r.pinned === 'false');
86
+ const restNoHot = rest.every(r => !r.hot || r.hot !== 'true');
87
+ const pinnedEntry = pinned?.find(r => r.rowKey === firstRow);
88
+ const pinFw_700 = pinnedEntry?.fw === '700';
89
+ const pinFlag = pinnedEntry?.pinned === 'true';
90
+ const othersRest = pinned ? pinned.filter(r => r.rowKey !== firstRow).every(r => r.fw === '600' && r.pinned === 'false') : false;
91
+
92
+ const results = {
93
+ rest_count_ge_2: rest.length >= 2,
94
+ rest_all_fw_600: restAll600,
95
+ rest_no_pin: restNoPin,
96
+ rest_no_hot: restNoHot,
97
+ pinned_target_fw_700: pinFw_700,
98
+ pinned_target_flag: pinFlag,
99
+ pinned_others_stay: othersRest,
100
+ source_wired: sourceWired,
101
+ };
102
+ const ok = Object.values(results).every(Boolean);
103
+ console.log(`${ok ? '✅' : '❌'} recent-row count fw pin:`, JSON.stringify(results),
104
+ '\n rest:', JSON.stringify(rest),
105
+ '\n pinned target:', JSON.stringify(pinnedEntry));
106
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,104 @@
1
+ /* Round 447 verification: recent-row freshness pip radius hover lift —
2
+ * r 2.0 → 2.5 on (isRowHovered || isRowPinned).
3
+ *
4
+ * Contract:
5
+ * - rest: every pip reports data-recent-row-freshness-radius '2' +
6
+ * lifted='false'
7
+ * - hover one row: that row's pip lifts to '2.5' + lifted='true'
8
+ * - siblings stay rest
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
15
+
16
+ const browser = await chromium.launch({ headless: true });
17
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
21
+ });
22
+ await ctx.route('**/api/hub/status*', async (route) => {
23
+ const r = await route.fetch();
24
+ const b = await r.json();
25
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
26
+ const mk = (alias, status) => ({
27
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
28
+ network_id: nid, project_dir: null,
29
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
30
+ });
31
+ await route.fulfill({ response: r, json: { ...b, sessions: [
32
+ mk('alpha', 'working'),
33
+ mk('beta', 'idle'),
34
+ mk('gamma', 'idle'),
35
+ ] } });
36
+ });
37
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({
38
+ json: { messages: [
39
+ { id: 'm1', from_alias: 'alpha', to_alias: 'beta', content: 'ping', created_at: fresh, network_id: 'default' },
40
+ { id: 'm2', from_alias: 'alpha', to_alias: 'gamma', content: 'pong', created_at: fresh, network_id: 'default' },
41
+ ] },
42
+ }));
43
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
44
+
45
+ const page = await ctx.newPage();
46
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
47
+ await page.waitForSelector('[data-recent-row-freshness]', { timeout: 15000 });
48
+ await page.waitForTimeout(400);
49
+
50
+ const readAll = () => page.evaluate(() => {
51
+ const ps = [...document.querySelectorAll('[data-recent-row-freshness]')];
52
+ return ps.map(p => ({
53
+ key: p.getAttribute('data-recent-row-freshness'),
54
+ r: parseFloat(p.getAttribute('data-recent-row-freshness-radius') || '0'),
55
+ lifted: p.getAttribute('data-recent-row-freshness-lifted'),
56
+ }));
57
+ });
58
+
59
+ const rest = await readAll();
60
+ const firstKey = rest[0]?.key;
61
+
62
+ // Hover the corresponding data-recent-row wrapper
63
+ let hover = null;
64
+ if (firstKey) {
65
+ const box = await page.evaluate((key) => {
66
+ const g = document.querySelector(`[data-recent-row="${key}"]`);
67
+ if (!g) return null;
68
+ const b = g.getBoundingClientRect();
69
+ return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
70
+ }, firstKey);
71
+ if (box) {
72
+ await page.mouse.move(box.x, box.y);
73
+ await page.waitForTimeout(300);
74
+ hover = await readAll();
75
+ await page.mouse.move(0, 0);
76
+ }
77
+ }
78
+
79
+ const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
80
+ const sourceWired = /r:\s*`\$\{\(isRowHovered \|\| isRowPinned\) \? 2\.5 : 2\.0\}px`/.test(fileText);
81
+
82
+ await browser.close();
83
+
84
+ const restAll_2_0 = rest.every(r => r.r === 2.0);
85
+ const restNoLifted = rest.every(r => r.lifted === 'false');
86
+ const hoveredEntry = hover?.find(r => r.key === firstKey);
87
+ const hoverR_2_5 = hoveredEntry?.r === 2.5;
88
+ const hoverLifted = hoveredEntry?.lifted === 'true';
89
+ const othersStayRest = hover ? hover.filter(r => r.key !== firstKey).every(r => r.r === 2.0 && r.lifted === 'false') : false;
90
+
91
+ const results = {
92
+ rest_count_ge_2: rest.length >= 2,
93
+ rest_all_r_2_0: restAll_2_0,
94
+ rest_no_lifted: restNoLifted,
95
+ hover_target_r_2_5: hoverR_2_5,
96
+ hover_target_lifted: hoverLifted,
97
+ hover_others_stay: othersStayRest,
98
+ source_wired: sourceWired,
99
+ };
100
+ const ok = Object.values(results).every(Boolean);
101
+ console.log(`${ok ? '✅' : '❌'} recent-row pip hover r:`, JSON.stringify(results),
102
+ '\n rest:', JSON.stringify(rest),
103
+ '\n hover target:', JSON.stringify(hoveredEntry));
104
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,96 @@
1
+ /* Round 443 verification: runtime badge inner-icon strokeWidth hover
2
+ * lift — 2.4 → 2.8 on node hover. Sibling to R208 outer ring sw lift.
3
+ *
4
+ * Contract:
5
+ * - rest: every runtime icon path reports stroke-width '2.4' +
6
+ * active='false'
7
+ * - hover one node: that icon path stroke-width '2.8' + active='true'
8
+ * - siblings stay rest
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 fresh = new Date(Date.now() - 60 * 1000).toISOString();
15
+
16
+ const browser = await chromium.launch({ headless: true });
17
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
18
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
19
+ await ctx.addInitScript(() => {
20
+ try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
21
+ });
22
+ await ctx.route('**/api/hub/status*', async (route) => {
23
+ const r = await route.fetch();
24
+ const b = await r.json();
25
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
26
+ const mk = (alias, status, runtime) => ({
27
+ alias, status, model: 'claude-opus-4', runtime,
28
+ network_id: nid, project_dir: null,
29
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
30
+ });
31
+ await route.fulfill({ response: r, json: { ...b, sessions: [
32
+ mk('alpha', 'working', 'claude-code-cli'),
33
+ mk('beta', 'idle', 'claude-code-cli'),
34
+ mk('gamma', 'working', 'claude-code-cli'),
35
+ ] } });
36
+ });
37
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
38
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
39
+
40
+ const page = await ctx.newPage();
41
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
42
+ await page.waitForSelector('[data-runtime-badge-icon]', { timeout: 15000 });
43
+ await page.waitForTimeout(400);
44
+
45
+ const readAll = () => page.evaluate(() => {
46
+ const ps = [...document.querySelectorAll('[data-runtime-badge-icon]')];
47
+ return ps.map(p => ({
48
+ alias: p.getAttribute('data-runtime-badge-icon'),
49
+ sw: p.getAttribute('stroke-width'),
50
+ active: p.getAttribute('data-runtime-badge-icon-active'),
51
+ }));
52
+ });
53
+
54
+ const rest = await readAll();
55
+ let hover = null;
56
+ const box = await page.evaluate(() => {
57
+ const t = document.querySelector('[data-node-alias-text="alpha"]');
58
+ if (!t) return null;
59
+ const node = t.closest('[data-node]');
60
+ const target = node || t;
61
+ const b = target.getBoundingClientRect();
62
+ return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
63
+ });
64
+ if (box) {
65
+ await page.mouse.move(box.x, box.y);
66
+ await page.waitForTimeout(300);
67
+ hover = await readAll();
68
+ await page.mouse.move(0, 0);
69
+ }
70
+
71
+ const fileText = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
72
+ const sourceWired = /strokeWidth=\{isNodeActive \? '2\.8' : '2\.4'\}/.test(fileText);
73
+
74
+ await browser.close();
75
+
76
+ const restAll_2_4 = rest.every(r => r.sw === '2.4');
77
+ const restNoActive = rest.every(r => r.active === 'false');
78
+ const hoveredEntry = hover?.find(r => r.alias === 'alpha');
79
+ const hoverSw_2_8 = hoveredEntry?.sw === '2.8';
80
+ const hoverActive = hoveredEntry?.active === 'true';
81
+ const othersRest = hover ? hover.filter(r => r.alias !== 'alpha').every(r => r.sw === '2.4' && r.active === 'false') : false;
82
+
83
+ const results = {
84
+ rest_count_ge_3: rest.length >= 3,
85
+ rest_all_sw_2_4: restAll_2_4,
86
+ rest_all_active_false: restNoActive,
87
+ hover_target_sw_2_8: hoverSw_2_8,
88
+ hover_target_active: hoverActive,
89
+ hover_others_stay: othersRest,
90
+ source_wired: sourceWired,
91
+ };
92
+ const ok = Object.values(results).every(Boolean);
93
+ console.log(`${ok ? '✅' : '❌'} runtime icon hover sw:`, JSON.stringify(results),
94
+ '\n rest:', JSON.stringify(rest),
95
+ '\n hover target:', JSON.stringify(hoveredEntry));
96
+ process.exit(ok ? 0 : 1);
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../agent-network-dashboard/app/lib/status.ts","../../../../../agent-network-dashboard/app/lib/time.ts","../../../../../agent-network-dashboard/app/components/utils.ts","../../../../../agent-network-dashboard/app/components/AliasAvatar.tsx","../../../../../agent-network-dashboard/app/components/EmptyState.tsx","../../../../../agent-network-dashboard/app/lib/hooks.ts"],"sourcesContent":["/** Single source of truth for task status colors. Both `/tasks` (chip\n * strip, badge, distribution bar) and the Overview Recent Activity row\n * used to ship their own incomplete maps; round 66 consolidates them\n * here so adding a new status updates every consumer at once.\n *\n * Order in `TASK_STATUSES` is chronological-ish: lifecycle progress on\n * the left, terminal-good (`closed`) in the middle, terminal-bad\n * (`failed`/`cancelled`/`expired`) on the right. */\n\nexport const TASK_STATUSES = [\n 'created',\n 'delivered',\n 'acked',\n 'running',\n 'replied',\n 'closed',\n 'failed',\n 'cancelled',\n 'expired',\n] as const;\n\nexport type TaskStatus = typeof TASK_STATUSES[number];\n\n/** Pill / chip background+text+border. Tailwind classes, not inlined hex,\n * because chips are static class names safe from purge. */\nexport const STATUS_CHIP_CLASS: Record<string, string> = {\n created: 'bg-gray-500/10 text-gray-400 border-gray-500/20',\n delivered: 'bg-blue-500/10 text-blue-300 border-blue-500/20',\n acked: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',\n running: 'bg-green-500/10 text-green-300 border-green-500/20',\n replied: 'bg-purple-500/10 text-purple-300 border-purple-500/20',\n closed: 'bg-gray-500/10 text-gray-500 border-gray-500/20',\n failed: 'bg-red-500/10 text-red-300 border-red-500/20',\n cancelled: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',\n expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',\n};\n\n/** Inline hex dots — used wherever Tailwind would purge dynamic class\n * names (`bg-${family}-400`). Style attribute carries the color. */\nexport const STATUS_DOT_HEX: Record<string, string> = {\n created: '#9ca3af',\n delivered: '#60a5fa',\n acked: '#22d3ee',\n running: '#4ade80',\n replied: '#a78bfa',\n closed: '#6b7280',\n failed: '#f87171',\n cancelled: '#facc15',\n expired: '#fb923c',\n};\n\n/** Session lifecycle (distinct from task lifecycle above). Shared by\n * /nodes status pills and /admin Online Sessions row chips so an\n * agent in `blocked` state reads the same color everywhere.\n * Round 91 — extracted from app/nodes/page.tsx. */\nexport const SESSION_STATUS_CHIP_CLASS: Record<string, string> = {\n working: 'bg-green-500/10 text-green-300 border-green-500/20',\n idle: 'bg-blue-500/10 text-blue-300 border-blue-500/20',\n blocked: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',\n error: 'bg-red-500/10 text-red-300 border-red-500/20',\n offline: 'bg-gray-500/10 text-gray-500 border-gray-500/20',\n};\n\n/** Text-only color for session status. Used where a chip background\n * would be too heavy — e.g. /node detail header status label. */\nexport const SESSION_STATUS_TEXT_CLASS: Record<string, string> = {\n working: 'text-green-400',\n idle: 'text-blue-400',\n blocked: 'text-yellow-400',\n error: 'text-red-400',\n offline: 'text-gray-500',\n};\n\n/** Solid bar segment background for the Tasks distribution bar. */\nexport const STATUS_BAR_CLASS: Record<string, string> = {\n created: 'bg-gray-500',\n delivered: 'bg-blue-500',\n acked: 'bg-cyan-500',\n running: 'bg-green-500',\n replied: 'bg-purple-500',\n closed: 'bg-gray-600',\n failed: 'bg-red-500',\n cancelled: 'bg-yellow-500',\n expired: 'bg-orange-500',\n};\n","/** Shared timestamp helpers for hub-sourced data.\n *\n * Background — the CommHub serialises timestamps SQL-style without a\n * zone (\"2026-05-15 06:00:28\"), but some test data uses full ISO\n * (\"…T06:00:28Z\"). `Date.parse` on bare SQL is **local-time** in every\n * browser the dashboard supports, so a UTC+8 operator silently sees\n * every timestamp 8 h older than reality (Round 35 dug this out via\n * the `isGhost` filter mis-fire).\n *\n * Round 38 / Loop consolidates parsing — TopoGraph (R35), ChatPopover\n * (R37) and utils.ts::timeAgo all mirrored the same SQL→UTC rewrite;\n * one source of truth here. */\n\n/** Parse a hub timestamp to ms-since-epoch, treating SQL-style strings\n * as UTC. ISO strings (with `T`) bypass the rewrite and are parsed as-is.\n * Returns null for empty / unparseable input. */\nexport function parseHubTime(dateStr: string | null | undefined): number | null {\n if (!dateStr) return null;\n const iso = dateStr.includes('T') ? dateStr : dateStr.replace(' ', 'T') + 'Z';\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n}\n\n/** Format `dateStr` as a short relative-time string (\"6m ago\" / \"2h ago\").\n * Future timestamps (clock skew) collapse to \"just now\". Returns null when\n * the input doesn't parse — callers can decide on a fallback. */\nexport function relativeAgo(dateStr: string | null | undefined): string | null {\n const t = parseHubTime(dateStr);\n if (t === null) return null;\n const s = Math.floor((Date.now() - t) / 1000);\n if (s < 0) return 'just now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n if (s < 86400) return `${Math.floor(s / 3600)}h ago`;\n return `${Math.floor(s / 86400)}d ago`;\n}\n","/** Round 82: strip the most common markdown markup from agent-to-agent\n * task / message bodies so single-line table previews read cleanly.\n * Full original content stays in the expanded row / drawer / title=. */\nexport function previewContent(raw: string | null | undefined): string {\n if (!raw) return '--';\n return raw\n .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1') // images: ![alt](src) → alt\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1') // links: [text](href) → text\n .replace(/`([^`]+)`/g, '$1') // inline code: `x` → x\n .replace(/\\s+/g, ' ') // collapse whitespace\n .trim() || '--';\n}\n\n// Round 44 / Loop: timeAgo now delegates to the shared lib/time helper.\n// The old in-line `replace + 'Z'` parse appended a Z to already-ISO\n// inputs (producing \"…ZZ\", browser-fragile) — strict-superset semantics\n// preserved for SQL-style inputs, fixed for ISO. Plus a 'just now' fallback\n// when clock skew puts the timestamp in the future. Five callers benefit:\n// /admin · /logs · /settings/networks · InboxPanel · /messages.\nimport { relativeAgo } from '../lib/time';\nexport function timeAgo(dateStr: string): string {\n return relativeAgo(dateStr) ?? '--';\n}\n\nexport function statusColor(status: string, hasSse: boolean): string {\n if (hasSse && status === 'working') return 'bg-green-500';\n if (hasSse && status === 'idle') return 'bg-emerald-400';\n if (hasSse) return 'bg-blue-400';\n if (status === 'offline') return 'bg-gray-500';\n return 'bg-yellow-400';\n}\n\nexport function formatUptime(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n if (h > 0) return `${h}h ${m}m`;\n return `${m}m`;\n}\n","/** Hue-hashed avatar pill for agent aliases. Same alias → same color across\n * every page (Messages, Nodes, TopoGraph). Use the `size` prop for inline\n * pills (16/20) vs card headers (28). Round 21 introduced the palette;\n * round 22 promotes it from app/messages to a shared component. */\n\nconst AVATAR_HUES = [180, 200, 220, 270, 300, 330, 30, 90];\n\nexport function aliasAvatarColors(alias: string): { bg: string; ring: string; text: string } {\n let h = 0;\n for (let i = 0; i < alias.length; i++) h = (h * 31 + alias.charCodeAt(i)) >>> 0;\n const hue = AVATAR_HUES[h % AVATAR_HUES.length];\n return {\n bg: `hsl(${hue} 55% 22%)`,\n ring: `hsl(${hue} 60% 45%)`,\n text: `hsl(${hue} 80% 78%)`,\n };\n}\n\nexport function aliasInitial(alias?: string): string {\n if (!alias) return '·';\n const ch = alias.trim().match(/[\\p{L}\\p{N}]/u)?.[0] || alias.trim()[0] || '·';\n return ch.toUpperCase();\n}\n\ninterface AliasAvatarProps {\n alias: string;\n size?: number;\n className?: string;\n}\n\nexport function AliasAvatar({ alias, size = 28, className = '' }: AliasAvatarProps) {\n const c = aliasAvatarColors(alias);\n const fs = Math.max(9, Math.round(size * 0.42));\n return (\n <span\n className={`anet-alias-avatar inline-flex items-center justify-center rounded-full border shrink-0 font-semibold ${className}`}\n style={{\n width: size,\n height: size,\n fontSize: fs,\n backgroundColor: c.bg,\n borderColor: c.ring,\n color: c.text,\n }}\n title={alias}\n aria-hidden\n >\n {aliasInitial(alias)}\n </span>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\n\nexport type EmptyVariant = 'nodes' | 'tasks' | 'messages' | 'logs' | 'tokens' | 'networks' | 'generic';\n\ninterface EmptyStateProps {\n /** Picks the icon glyph and default copy if title/sub omitted. */\n variant?: EmptyVariant;\n /** Optional override headline. */\n title?: string;\n /** Optional override sub-copy. */\n sub?: string;\n /** Optional CTA: text + href (internal) or onClick. */\n cta?: { label: string; href?: string; onClick?: () => void };\n /** Compact mode for in-card empty states (smaller padding). */\n compact?: boolean;\n}\n\nconst DEFAULTS: Record<EmptyVariant, { title: string; sub: string }> = {\n nodes: { title: 'No agents in this network', sub: 'Agent sessions will appear here once they connect to the CommHub.' },\n tasks: { title: 'No tasks yet', sub: 'Tasks will appear here when agents send them via CommHub.' },\n messages: { title: 'No messages', sub: 'Messages between agents will appear here.' },\n logs: { title: 'No audit logs', sub: 'Events will appear here when users register, login, or perform actions.' },\n tokens: { title: 'No API tokens', sub: 'Create one to authenticate CLI tools and external integrations.' },\n networks: { title: 'No networks found', sub: 'Create one or sign in with V3 auth to see your networks.' },\n generic: { title: 'Nothing here yet', sub: 'Data will appear here once available.' },\n};\n\n/**\n * Minimal monochrome SVG glyphs per variant. No filled shapes, no gradients,\n * no AI-decoration — just thin-stroke line art that fades into the page.\n * 64×64 viewBox; rendered at 56×56 (compact 40×40).\n */\nfunction Glyph({ variant, size }: { variant: EmptyVariant; size: number }) {\n const s = { width: size, height: size };\n const baseProps = {\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.25,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const,\n };\n\n switch (variant) {\n case 'nodes':\n // Mesh with dashed edges = \"nodes will land here\"\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <circle cx=\"32\" cy=\"14\" r=\"4\" />\n <circle cx=\"14\" cy=\"44\" r=\"4\" />\n <circle cx=\"50\" cy=\"44\" r=\"4\" />\n <line x1=\"32\" y1=\"18\" x2=\"14\" y2=\"40\" strokeDasharray=\"3 3\" opacity=\"0.6\" />\n <line x1=\"32\" y1=\"18\" x2=\"50\" y2=\"40\" strokeDasharray=\"3 3\" opacity=\"0.6\" />\n <line x1=\"18\" y1=\"44\" x2=\"46\" y2=\"44\" strokeDasharray=\"3 3\" opacity=\"0.6\" />\n </g>\n </svg>\n );\n case 'tasks':\n // Empty checkbox list\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <rect x=\"14\" y=\"14\" width=\"36\" height=\"6\" rx=\"1.5\" />\n <rect x=\"14\" y=\"26\" width=\"36\" height=\"6\" rx=\"1.5\" opacity=\"0.6\" />\n <rect x=\"14\" y=\"38\" width=\"36\" height=\"6\" rx=\"1.5\" opacity=\"0.35\" />\n </g>\n </svg>\n );\n case 'messages':\n // Speech bubble outline\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <path d=\"M14 18 h36 a3 3 0 0 1 3 3 v18 a3 3 0 0 1 -3 3 h-18 l-8 6 v-6 h-10 a3 3 0 0 1 -3 -3 v-18 a3 3 0 0 1 3 -3 z\" />\n <line x1=\"22\" y1=\"28\" x2=\"42\" y2=\"28\" opacity=\"0.5\" />\n <line x1=\"22\" y1=\"34\" x2=\"36\" y2=\"34\" opacity=\"0.5\" />\n </g>\n </svg>\n );\n case 'logs':\n // Document with lines\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <path d=\"M18 12 h22 l8 8 v32 a2 2 0 0 1 -2 2 h-28 a2 2 0 0 1 -2 -2 v-38 a2 2 0 0 1 2 -2 z\" />\n <path d=\"M40 12 v8 h8\" opacity=\"0.6\" />\n <line x1=\"24\" y1=\"32\" x2=\"40\" y2=\"32\" opacity=\"0.55\" />\n <line x1=\"24\" y1=\"38\" x2=\"40\" y2=\"38\" opacity=\"0.4\" />\n <line x1=\"24\" y1=\"44\" x2=\"34\" y2=\"44\" opacity=\"0.25\" />\n </g>\n </svg>\n );\n case 'tokens':\n // Key outline\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <circle cx=\"22\" cy=\"32\" r=\"8\" />\n <line x1=\"30\" y1=\"32\" x2=\"54\" y2=\"32\" />\n <line x1=\"44\" y1=\"32\" x2=\"44\" y2=\"38\" />\n <line x1=\"50\" y1=\"32\" x2=\"50\" y2=\"40\" />\n </g>\n </svg>\n );\n case 'networks':\n // Globe-ish concentric ovals\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <circle cx=\"32\" cy=\"32\" r=\"18\" />\n <ellipse cx=\"32\" cy=\"32\" rx=\"18\" ry=\"9\" opacity=\"0.55\" />\n <line x1=\"14\" y1=\"32\" x2=\"50\" y2=\"32\" opacity=\"0.55\" />\n <line x1=\"32\" y1=\"14\" x2=\"32\" y2=\"50\" opacity=\"0.55\" />\n </g>\n </svg>\n );\n case 'generic':\n default:\n // Soft sparkle outline\n return (\n <svg viewBox=\"0 0 64 64\" {...s}>\n <g {...baseProps}>\n <circle cx=\"32\" cy=\"32\" r=\"14\" strokeDasharray=\"3 3\" opacity=\"0.6\" />\n <circle cx=\"32\" cy=\"32\" r=\"3\" />\n </g>\n </svg>\n );\n }\n}\n\nexport function EmptyState({ variant = 'generic', title, sub, cta, compact = false }: EmptyStateProps) {\n const d = DEFAULTS[variant];\n const headline = title ?? d.title;\n const subcopy = sub ?? d.sub;\n const iconSize = compact ? 40 : 56;\n\n return (\n <div className={`text-center ${compact ? 'py-8' : 'py-16'} px-4`} role=\"status\">\n <div className=\"anet-empty-glyph inline-flex items-center justify-center mb-4 text-gray-500\" aria-hidden>\n <Glyph variant={variant} size={iconSize} />\n </div>\n <h3 className={`font-medium text-gray-300 ${compact ? 'text-sm' : 'text-base'}`}>{headline}</h3>\n {subcopy && (\n <p className={`text-gray-500 ${compact ? 'text-xs mt-1.5' : 'text-sm mt-2'} max-w-md mx-auto leading-relaxed`}>\n {subcopy}\n </p>\n )}\n {cta && (\n <div className=\"mt-4\">\n {cta.href ? (\n <Link href={cta.href} className=\"inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300\">\n {cta.label}\n <span aria-hidden>→</span>\n </Link>\n ) : (\n <button onClick={cta.onClick} className=\"inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300\">\n {cta.label}\n <span aria-hidden>→</span>\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** Round 105 (issue #90): centered card shell so the Overview empty state\n * reads as an intentional, layout-aligned card instead of bare text\n * floating in the content column. */\nfunction EmptyCard({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"max-w-2xl mx-auto rounded-xl border border-[#2a2a4a] bg-[#111128] shadow-lg shadow-black/20\">\n {children}\n </div>\n );\n}\n\n/**\n * Overview-specific variant. Three cases:\n * 1. network-mismatch — agents exist globally, none in this network\n * 2. agents-offline — 0 registered now BUT task history exists, so this\n * is NOT a first run (round 105 / issue #90: showing \"Spin up your\n * first agent\" next to \"acked: 499\" was misleading)\n * 3. true first-run — 0 agents, 0 history → quickstart command\n */\nexport function NodesEmptyState({\n hint,\n taskHistoryCount = 0,\n}: {\n hint?: { global_count?: number; filtered_network?: string };\n taskHistoryCount?: number;\n}) {\n if (hint?.global_count) {\n return (\n <EmptyCard>\n <EmptyState\n variant=\"nodes\"\n title=\"No agents in this network\"\n sub={`Server has ${hint.global_count} nodes globally, but none are registered to the current network. Switch network or contact admin.`}\n />\n </EmptyCard>\n );\n }\n\n // Round 105 (issue #90): there's task history but no agents online right\n // now — they finished or disconnected. Don't pitch a first-run setup;\n // point at the history instead.\n if (taskHistoryCount > 0) {\n return (\n <EmptyCard>\n <EmptyState\n variant=\"nodes\"\n title=\"No agents online\"\n sub={`Every agent in this network is currently offline. ${taskHistoryCount.toLocaleString()} task${taskHistoryCount === 1 ? '' : 's'} in history — they may have finished their work or disconnected.`}\n cta={{ label: 'View task history', href: '/tasks' }}\n />\n </EmptyCard>\n );\n }\n\n // Round 52: true empty state (zero agents anywhere) — show the\n // quickstart command inline so users don't have to leave the dashboard\n // to figure out how to spin up their first agent.\n return (\n <EmptyCard>\n <div className=\"text-center py-16 px-4\" role=\"status\">\n <div className=\"anet-empty-glyph inline-flex items-center justify-center mb-4 text-gray-500\" aria-hidden>\n <svg viewBox=\"0 0 64 64\" width={56} height={56}>\n <g stroke=\"currentColor\" strokeWidth=\"1.5\" fill=\"none\">\n <rect x=\"10\" y=\"20\" width=\"44\" height=\"28\" rx=\"2\" />\n <rect x=\"20\" y=\"32\" width=\"6\" height=\"8\" opacity=\"0.5\" />\n <rect x=\"32\" y=\"32\" width=\"6\" height=\"8\" opacity=\"0.5\" />\n <rect x=\"44\" y=\"32\" width=\"4\" height=\"8\" opacity=\"0.5\" />\n <line x1=\"10\" y1=\"26\" x2=\"54\" y2=\"26\" opacity=\"0.4\" />\n <circle cx=\"14\" cy=\"23\" r=\"0.8\" fill=\"currentColor\" />\n </g>\n </svg>\n </div>\n <h3 className=\"font-medium text-gray-300 text-base\">Spin up your first agent</h3>\n <p className=\"text-gray-500 text-sm mt-2 max-w-md mx-auto leading-relaxed\">\n Run this in a fresh terminal to register an agent with this CommHub:\n </p>\n <div className=\"mt-4 inline-block\">\n <QuickstartCommand cmd=\"npx --yes @sleep2agi/agent-network init\" />\n </div>\n <div className=\"mt-3\">\n <a\n href=\"https://anet.sh\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-cyan-300\"\n >\n Full quickstart guide\n <span aria-hidden>→</span>\n </a>\n </div>\n </div>\n </EmptyCard>\n );\n}\n\n/** Code block + inline copy button used by the empty-Overview first-run\n * CTA. State lives here so the parent stays stateless. */\nfunction QuickstartCommand({ cmd }: { cmd: string }) {\n const [copied, setCopied] = useState(false);\n const onCopy = async () => {\n try {\n await navigator.clipboard.writeText(cmd);\n setCopied(true);\n setTimeout(() => setCopied(false), 1800);\n } catch {}\n };\n return (\n <div className=\"anet-empty-cmd flex items-center gap-2 bg-[#0a0a15] border border-[#2a2a4a] rounded-lg pl-4 pr-1.5 py-1.5 text-xs sm:text-sm\">\n <code className=\"text-cyan-300 font-mono select-all\">{cmd}</code>\n <button\n type=\"button\"\n onClick={onCopy}\n aria-label={copied ? 'Copied' : 'Copy command'}\n className=\"shrink-0 rounded-md px-2 py-1.5 text-[11px] text-gray-500 hover:text-gray-200 hover:bg-[#1a1a2a] transition-colors\"\n >\n {copied ? (\n <span className=\"flex items-center gap-1 text-green-400\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n Copied\n </span>\n ) : (\n <span className=\"flex items-center gap-1\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n Copy\n </span>\n )}\n </button>\n </div>\n );\n}\n","import useSWR from 'swr';\nimport { Session, Health, AnetConfig } from '../components/types';\nimport { useNetworkId } from './network-context';\n\nconst fetcher = async (url: string) => {\n const res = await fetch(url);\n if (res.status === 401) {\n window.location.assign('/login');\n throw new Error('unauthorized');\n }\n return res.json();\n};\n\nconst SWR_OPTIONS = { refreshInterval: 5000, dedupingInterval: 3000 };\n\n/** Append network_id to URL if set */\nfunction withNetwork(url: string, networkId: string): string {\n if (!networkId) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}network_id=${encodeURIComponent(networkId)}`;\n}\n\nexport function useSessions() {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR<{ sessions: Session[]; _hint?: { global_count?: number; filtered_network?: string } }>(\n withNetwork('/api/hub/status', networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { sessions: data?.sessions || [], hint: data?._hint, error, isLoading };\n}\n\nexport function useHealth() {\n const { data, error } = useSWR<Health>('/api/hub/health', fetcher, SWR_OPTIONS);\n return { health: data || null, error };\n}\n\nexport function useAnetConfig() {\n const { data } = useSWR<AnetConfig>('/api/anet/config', fetcher, { refreshInterval: 30000 });\n return { config: data || null };\n}\n\nexport function useTasks(params?: Record<string, string>) {\n const { networkId } = useNetworkId();\n const query = new URLSearchParams({ limit: '100', ...params }).toString();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/tasks?${query}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return {\n tasks: data?.tasks || [],\n count: data?.count ?? 0,\n source: data?.source,\n error,\n isLoading,\n };\n}\n\nexport function useStats() {\n const { networkId } = useNetworkId();\n const { data, error } = useSWR(withNetwork('/api/hub/stats', networkId), fetcher, SWR_OPTIONS);\n return { stats: data?.ok ? data : null, error };\n}\n\nexport function useLicense() {\n const { data, error } = useSWR('/api/hub/license', fetcher, { refreshInterval: 60000 });\n return { license: data?.ok ? data : null, error };\n}\n\nexport function useMessages(limit = 100) {\n const { networkId } = useNetworkId();\n const { data, error, isLoading } = useSWR(\n withNetwork(`/api/hub/messages?limit=${limit}`, networkId),\n fetcher,\n SWR_OPTIONS,\n );\n return { messages: data?.messages || [], error, isLoading };\n}\n\nexport function useNodeSession(alias: string) {\n const { data, error, isLoading } = useSWR(\n alias ? `/api/hub/session?alias=${encodeURIComponent(alias)}` : null,\n fetcher,\n SWR_OPTIONS,\n );\n return {\n session: data?.session || null,\n inbox: data?.inbox || [],\n sse: data?.sse || 0,\n error,\n isLoading,\n };\n}\n"],"names":["TASK_STATUSES","STATUS_CHIP_CLASS","created","delivered","acked","running","replied","closed","failed","cancelled","expired","STATUS_DOT_HEX","SESSION_STATUS_CHIP_CLASS","working","idle","blocked","error","offline","SESSION_STATUS_TEXT_CLASS","STATUS_BAR_CLASS","parseHubTime","dateStr","iso","includes","replace","t","Date","parse","Number","isFinite","relativeAgo","s","Math","floor","now","AVATAR_HUES","aliasAvatarColors","alias","h","i","length","charCodeAt","hue","bg","ring","text","aliasInitial","ch","trim","match","toUpperCase","AliasAvatar","size","className","c","fs","max","round","style","width","height","fontSize","backgroundColor","borderColor","color","title","DEFAULTS","nodes","sub","tasks","messages","logs","tokens","networks","generic","Glyph","variant","baseProps","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","viewBox","cx","cy","r","x1","y1","x2","y2","strokeDasharray","opacity","x","y","rx","d","ry","EmptyState","cta","compact","headline","subcopy","iconSize","role","href","label","onClick","EmptyCard","children","NodesEmptyState","hint","taskHistoryCount","global_count","toLocaleString","QuickstartCommand","cmd","target","rel","copied","setCopied","onCopy","navigator","clipboard","writeText","setTimeout","type","fetcher","url","res","fetch","status","window","location","assign","Error","json","SWR_OPTIONS","refreshInterval","dedupingInterval","withNetwork","networkId","sep","encodeURIComponent","useSessions","data","isLoading","sessions","_hint","useHealth","health","useAnetConfig","config","useTasks","params","query","URLSearchParams","limit","toString","count","source","useStats","stats","ok","useLicense","license","useMessages","useNodeSession","session","inbox","sse"],"mappings":"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"}
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,70286,e=>{"use strict";e.s(["DASHBOARD_VERSION",0,"0.5.1-preview.98"],70286)},48941,e=>{"use strict";var t=e.i(22381),r=e.i(23910),a=e.i(70286);e.s(["default",0,function(){let[e,s]=(0,r.useState)("login"),[n,o]=(0,r.useState)(""),[i,l]=(0,r.useState)(""),[c,d]=(0,r.useState)(!1),[x,g]=(0,r.useState)(""),[h,m]=(0,r.useState)(!1),u=async t=>{t.preventDefault(),m(!0),g("");try{let t=await fetch("/api/auth/v3",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,username:n,password:i})}),r=await t.json();if(r.ok){r.token&&sessionStorage.setItem("anet_v3_auth",JSON.stringify({user:r.user,token:r.token,networks:r.networks||[],currentNetwork:r.network_id||r.networks?.[0]?.network_id||""})),window.location.assign("/");return}g(r.error||"Login failed")}catch{g("Connection failed")}m(!1)};return(0,t.jsxs)("main",{className:"min-h-screen bg-[#0a0a1a] text-gray-100 font-mono flex items-center justify-center relative overflow-hidden px-4 py-10 sm:py-16",children:[(0,t.jsx)("div",{className:"absolute inset-0 pointer-events-none anet-login-bg","aria-hidden":!0}),(0,t.jsxs)("div",{className:"relative w-full max-w-sm",children:[(0,t.jsxs)("div",{className:"text-center mb-7",children:[(0,t.jsx)("div",{className:"inline-flex items-center justify-center w-16 h-16 mb-4 rounded-2xl bg-[#111128] border border-[#2a2a4a] anet-login-mark",children:(0,t.jsxs)("svg",{className:"w-9 h-9",viewBox:"0 0 32 32","aria-hidden":!0,children:[(0,t.jsx)("circle",{cx:"16",cy:"16",r:"10",fill:"none",stroke:"currentColor",strokeWidth:"1.5",opacity:"0.25",className:"text-cyan-400 anet-login-mark-ring"}),(0,t.jsx)("line",{x1:"16",y1:"10",x2:"10",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.5",className:"text-cyan-400 anet-login-mark-edge"}),(0,t.jsx)("line",{x1:"16",y1:"10",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.5",className:"text-cyan-400 anet-login-mark-edge"}),(0,t.jsx)("line",{x1:"10",y1:"20",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.5",className:"text-cyan-400 anet-login-mark-edge"}),(0,t.jsx)("circle",{cx:"16",cy:"10",r:"3",fill:"currentColor",className:"text-cyan-400 anet-login-mark-node-a"}),(0,t.jsx)("circle",{cx:"10",cy:"20",r:"3",fill:"currentColor",className:"text-green-400 anet-login-mark-node-b"}),(0,t.jsx)("circle",{cx:"22",cy:"20",r:"3",fill:"currentColor",className:"text-violet-400 anet-login-mark-node-c"})]})}),(0,t.jsx)("h1",{className:"text-[22px] sm:text-2xl font-semibold text-white tracking-tight",children:"Agent Network"}),(0,t.jsx)("p",{className:"text-[13px] text-gray-500 mt-1.5 leading-snug",children:"login"===e?(0,t.jsxs)(t.Fragment,{children:["Welcome back · ",(0,t.jsx)("span",{className:"text-gray-600",children:"Tasks · Mesh · Messages"})]}):(0,t.jsxs)(t.Fragment,{children:["Create your account · ",(0,t.jsx)("span",{className:"text-gray-600",children:"Free preview · no credit card"})]})})]}),(0,t.jsx)("div",{className:"flex rounded-lg border border-[#2a2a4a] bg-[#111128] p-1 mb-4",children:["login","register"].map(r=>(0,t.jsx)("button",{type:"button",onClick:()=>{s(r),g("")},className:`flex-1 rounded-md px-3 py-2 text-sm transition-colors ${e===r?"bg-cyan-500/10 text-cyan-300":"text-gray-500 hover:text-gray-200"}`,children:"login"===r?"Sign in":"Register"},r))}),(0,t.jsxs)("form",{onSubmit:u,className:"border border-[#2a2a4a] bg-[#111128]/80 backdrop-blur-sm rounded-xl p-6 shadow-2xl shadow-black/30",children:[(0,t.jsx)("label",{htmlFor:"username",className:"block text-xs text-gray-500 mb-2 uppercase tracking-wider",children:"Username"}),(0,t.jsx)("input",{id:"username",type:"text",value:n,onChange:e=>o(e.target.value),autoFocus:!0,placeholder:"Enter username",className:"w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all mb-4"}),(0,t.jsx)("label",{htmlFor:"password",className:"block text-xs text-gray-500 mb-2 uppercase tracking-wider",children:"Password"}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("input",{id:"password",type:c?"text":"password",value:i,onChange:e=>l(e.target.value),placeholder:"Enter password",className:"w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 pr-11 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all"}),(0,t.jsx)("button",{type:"button",onClick:()=>d(e=>!e),tabIndex:-1,"aria-label":c?"Hide password":"Show password",className:"absolute inset-y-0 right-0 flex items-center px-3 text-gray-600 hover:text-gray-300 transition-colors",children:c?(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("path",{d:"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"}),(0,t.jsx)("line",{x1:"1",y1:"1",x2:"23",y2:"23"})]}):(0,t.jsxs)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,t.jsx)("path",{d:"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"}),(0,t.jsx)("circle",{cx:"12",cy:"12",r:"3"})]})})]}),x&&(0,t.jsx)("div",{className:"mt-3 text-sm text-red-300 bg-red-500/5 border border-red-500/10 rounded-lg px-3 py-2",children:x}),(0,t.jsxs)("button",{type:"submit",disabled:h||!i||!n.trim(),className:"mt-5 w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none",children:[h&&(0,t.jsxs)("svg",{"aria-hidden":!0,className:"w-4 h-4 animate-spin",viewBox:"0 0 24 24",fill:"none",children:[(0,t.jsx)("circle",{cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"3",opacity:"0.25"}),(0,t.jsx)("path",{d:"M4 12a8 8 0 018-8",stroke:"currentColor",strokeWidth:"3",strokeLinecap:"round"})]}),(0,t.jsx)("span",{children:h?"login"===e?"Signing in…":"Registering…":"login"===e?"Sign in":"Create account"})]})]}),(0,t.jsxs)("p",{className:"text-center text-[11px] text-gray-700 mt-6",children:["Sleep2AGI · Apache-2.0 · ",(0,t.jsx)("a",{href:"https://anet.sh",className:"hover:text-gray-500 transition-colors",children:"anet.sh"}),(0,t.jsx)("span",{className:"mx-1 text-gray-800",children:"·"}),(0,t.jsxs)("span",{className:"font-mono",title:"@sleep2agi/agent-network-dashboard",children:["v",a.DASHBOARD_VERSION]})]})]})]})}])}]);