neohive 6.0.2 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,264 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Neohive design system</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
10
+ <link rel="stylesheet" href="/design-system.css">
11
+ <style>
12
+ .nh-ds-page { margin: 0; min-height: 100vh; }
13
+ .nh-ds-layout { display: flex; min-height: 100vh; }
14
+ .nh-ds-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
15
+ .nh-ds-content { flex: 1; padding: var(--nh-space-6); overflow: auto; }
16
+ .nh-ds-grid { display: grid; gap: var(--nh-space-6); }
17
+ @media (min-width: 960px) {
18
+ .nh-ds-grid--3 { grid-template-columns: repeat(3, 1fr); }
19
+ }
20
+ .nh-ds-stack { display: flex; flex-direction: column; gap: var(--nh-space-4); }
21
+ .nh-ds-row { display: flex; flex-wrap: wrap; gap: var(--nh-space-2); align-items: center; }
22
+ .nh-ds-swatch-row { display: flex; flex-wrap: wrap; gap: var(--nh-space-3); }
23
+ .nh-ds-swatch-item { display: flex; flex-direction: column; gap: var(--nh-space-1); width: 72px; }
24
+ .nh-ds-swatch-item span { font-size: 10px; color: var(--nh-text-secondary); line-height: 1.35; }
25
+ .nh-ds-h1 { font-size: 20px; font-weight: 600; margin: 0 0 var(--nh-space-6); }
26
+ .nh-ds-h2 { font-size: 14px; font-weight: 500; margin: 0 0 var(--nh-space-3); color: var(--nh-text-primary); }
27
+ .nh-ds-label { font-size: 12px; color: var(--nh-text-secondary); display: block; margin-bottom: var(--nh-space-2); }
28
+ .nh-ds-preview-board { display: flex; gap: var(--nh-space-4); overflow-x: auto; padding-bottom: var(--nh-space-2); min-height: 280px; }
29
+ .nh-ds-preview-board .nh-kanban-col { flex: 1; min-width: 200px; max-width: 280px; }
30
+ </style>
31
+ </head>
32
+ <body class="nh-ds nh-ds-page">
33
+ <div class="nh-ds-layout">
34
+ <aside class="nh-sidebar nh-ds" style="width: 256px; flex-shrink: 0; display: flex; flex-direction: column; min-height: 100vh;">
35
+ <div class="nh-topbar" style="border-right: 0;">
36
+ <div class="nh-ds-row" style="gap: var(--nh-space-2);">
37
+ <div style="width: 24px; height: 24px; border-radius: var(--nh-radius-sm); background: var(--nh-accent); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #fff;">N</div>
38
+ <span style="font-weight: 600; font-size: 14px;">Neohive</span>
39
+ </div>
40
+ </div>
41
+ <div style="flex: 1; overflow-y: auto; padding: var(--nh-space-4) var(--nh-space-3); display: flex; flex-direction: column; gap: var(--nh-space-6);">
42
+ <nav class="nh-ds-stack" style="gap: var(--nh-space-1);">
43
+ <div class="nh-sidebar__section-label"><span>Menu</span></div>
44
+ <a class="nh-nav-link" href="#">Overview</a>
45
+ <a class="nh-nav-link" href="#">Messages</a>
46
+ <a class="nh-nav-link nh-nav-link--active" href="#">Tasks</a>
47
+ <a class="nh-nav-link" href="#">Workflows</a>
48
+ </nav>
49
+ <div>
50
+ <div class="nh-sidebar__section-label"><span>Agents</span></div>
51
+ <div class="nh-agent-chip">
52
+ <span class="nh-avatar-fallback">A</span>
53
+ <div style="flex: 1; min-width: 0;">
54
+ <div class="nh-agent-chip__name" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">Agent</div>
55
+ <div class="nh-agent-chip__status" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">lead · offline</div>
56
+ </div>
57
+ <span class="nh-dot"></span>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </aside>
62
+ <div class="nh-ds-main nh-ds">
63
+ <header class="nh-topbar">
64
+ <div class="nh-ds-row">
65
+ <span class="nh-dot"></span>
66
+ <span style="font-size: 14px; color: var(--nh-text-secondary);">Reference layout</span>
67
+ </div>
68
+ <div class="nh-ds-row">
69
+ <span class="nh-dot nh-dot--live" title="Online"></span>
70
+ <span class="nh-dot"></span>
71
+ </div>
72
+ </header>
73
+ <div class="nh-ds-content">
74
+ <h1 class="nh-ds-h1">Design system</h1>
75
+
76
+ <section class="nh-spec-panel nh-ds-stack" style="margin-bottom: var(--nh-space-6);">
77
+ <h2 class="nh-ds-h2" style="font-size: 18px; margin-bottom: var(--nh-space-4);">Color palette</h2>
78
+ <div class="nh-ds-grid nh-ds-grid--3">
79
+ <div>
80
+ <h3 class="nh-ds-h2">Primary &amp; neutrals</h3>
81
+ <div class="nh-ds-swatch-row">
82
+ <div class="nh-ds-swatch-item">
83
+ <div class="nh-swatch" style="background: var(--nh-accent);"></div>
84
+ <span>#F59E0B<br>Amber accent</span>
85
+ </div>
86
+ <div class="nh-ds-swatch-item">
87
+ <div class="nh-swatch nh-swatch--border" style="background: var(--nh-charcoal);"></div>
88
+ <span>#121212<br>Charcoal</span>
89
+ </div>
90
+ <div class="nh-ds-swatch-item">
91
+ <div class="nh-swatch" style="background: var(--nh-graphite);"></div>
92
+ <span>#172B37<br>Graphite</span>
93
+ </div>
94
+ <div class="nh-ds-swatch-item">
95
+ <div class="nh-swatch" style="background: var(--nh-gray);"></div>
96
+ <span>#D1D5DB<br>Light gray</span>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ <div>
101
+ <h3 class="nh-ds-h2">Surfaces</h3>
102
+ <div class="nh-ds-swatch-row">
103
+ <div class="nh-ds-swatch-item">
104
+ <div class="nh-swatch nh-swatch--border" style="background: var(--nh-bg);"></div>
105
+ <span>#0F0F10<br>Background</span>
106
+ </div>
107
+ <div class="nh-ds-swatch-item">
108
+ <div class="nh-swatch" style="background: var(--nh-sidebar);"></div>
109
+ <span>#161618<br>Sidebar</span>
110
+ </div>
111
+ <div class="nh-ds-swatch-item">
112
+ <div class="nh-swatch" style="background: var(--nh-card);"></div>
113
+ <span>#1C1C1F<br>Card</span>
114
+ </div>
115
+ <div class="nh-ds-swatch-item">
116
+ <div class="nh-swatch" style="background: var(--nh-card-hover);"></div>
117
+ <span>#232326<br>Card hover</span>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ <div>
122
+ <h3 class="nh-ds-h2">Semantic</h3>
123
+ <div class="nh-ds-swatch-row">
124
+ <div class="nh-ds-swatch-item">
125
+ <div class="nh-swatch" style="background: var(--nh-green);"></div>
126
+ <span>#10B981<br>Success</span>
127
+ </div>
128
+ <div class="nh-ds-swatch-item">
129
+ <div class="nh-swatch" style="background: var(--nh-amber);"></div>
130
+ <span>#F59E0B<br>Warning</span>
131
+ </div>
132
+ <div class="nh-ds-swatch-item">
133
+ <div class="nh-swatch" style="background: var(--nh-blue);"></div>
134
+ <span>#3B82F6<br>Info</span>
135
+ </div>
136
+ </div>
137
+ <div class="nh-ds-swatch-row" style="margin-top: var(--nh-space-3);">
138
+ <div class="nh-ds-swatch-item">
139
+ <div class="nh-swatch" style="background: var(--nh-red);"></div>
140
+ <span>Error / danger</span>
141
+ </div>
142
+ <div class="nh-ds-swatch-item">
143
+ <div class="nh-swatch" style="background: var(--nh-orange);"></div>
144
+ <span>Orange</span>
145
+ </div>
146
+ <div class="nh-ds-swatch-item">
147
+ <div class="nh-swatch" style="background: var(--nh-purple);"></div>
148
+ <span>Purple</span>
149
+ </div>
150
+ <div class="nh-ds-swatch-item">
151
+ <div class="nh-swatch" style="background: var(--nh-yellow);"></div>
152
+ <span>Yellow</span>
153
+ </div>
154
+ </div>
155
+ <p class="nh-ds-label" style="margin-top: var(--nh-space-3);">Done lane: <code style="color: var(--nh-text-secondary);">--nh-success-surface</code> / <code style="color: var(--nh-text-secondary);">--nh-success-card</code>. Dividers: <code style="color: var(--nh-text-secondary);">--nh-divider</code> / <code style="color: var(--nh-text-secondary);">--nh-divider-strong</code>. Light theme: <code style="color: var(--nh-text-secondary);">data-theme="light"</code> on <code style="color: var(--nh-text-secondary);">&lt;html&gt;</code> (dashboard sets this via Theme).</p>
156
+ </div>
157
+ </div>
158
+ </section>
159
+
160
+ <section class="nh-ds-stack" style="margin-bottom: var(--nh-space-6);">
161
+ <h2 class="nh-ds-h2" style="font-size: 18px;">Presence dots (token-backed)</h2>
162
+ <p class="nh-ds-label">Use <code style="color: var(--nh-text-primary);">nh-presence-dot</code> + modifier; no hex in JS.</p>
163
+ <div class="nh-ds-row" style="gap: var(--nh-space-4); flex-wrap: wrap;">
164
+ <span class="nh-presence-dot nh-presence-dot--working" title="working"></span>
165
+ <span class="nh-presence-dot nh-presence-dot--listening" title="listening"></span>
166
+ <span class="nh-presence-dot nh-presence-dot--idle" title="idle"></span>
167
+ <span class="nh-presence-dot nh-presence-dot--offline" title="offline"></span>
168
+ </div>
169
+ </section>
170
+
171
+ <section class="nh-ds-grid nh-ds-grid--3" style="margin-bottom: var(--nh-space-6);">
172
+ <div>
173
+ <h2 class="nh-ds-h2">Buttons</h2>
174
+ <span class="nh-ds-label">Primary</span>
175
+ <button type="button" class="nh-btn nh-btn--primary" style="width: 100%;">Primary action</button>
176
+ <span class="nh-ds-label" style="margin-top: var(--nh-space-4);">Secondary</span>
177
+ <button type="button" class="nh-btn nh-btn--secondary" style="width: 100%;">Secondary action</button>
178
+ </div>
179
+ <div>
180
+ <h2 class="nh-ds-h2">Status pills</h2>
181
+ <div class="nh-ds-row">
182
+ <span class="nh-pill nh-pill--review nh-pill--lg">In review</span>
183
+ <span class="nh-pill nh-pill--done nh-pill--lg">Done</span>
184
+ </div>
185
+ </div>
186
+ <div>
187
+ <h2 class="nh-ds-h2">Task card</h2>
188
+ <article class="nh-card nh-card--interactive">
189
+ <h3 class="nh-card__title">Refactor API endpoint for optimization</h3>
190
+ <p class="nh-card__body">Analyze and restructure the data flow to improve throughput and clarity for consumers of the API.</p>
191
+ <div class="nh-card__footer">
192
+ <div class="nh-ds-row">
193
+ <span class="nh-avatar-fallback">S</span>
194
+ <span class="nh-pill nh-pill--review">In review</span>
195
+ </div>
196
+ <span class="nh-card__meta">2h ago</span>
197
+ </div>
198
+ </article>
199
+ </div>
200
+ </section>
201
+
202
+ <h2 class="nh-ds-h2" style="font-size: 18px;">Kanban preview</h2>
203
+ <div class="nh-ds-preview-board">
204
+ <div class="nh-kanban-col">
205
+ <div class="nh-kanban-col__head">
206
+ <h3 class="nh-kanban-col__title">Pending <span class="nh-kanban-col__count">(0)</span></h3>
207
+ </div>
208
+ <div class="nh-kanban-col__empty">
209
+ <div class="nh-kanban-col__empty-icon">?</div>
210
+ <p class="nh-kanban-col__empty-text">No active tasks</p>
211
+ </div>
212
+ </div>
213
+ <div class="nh-kanban-col">
214
+ <div class="nh-kanban-col__head nh-kanban-col__head--sticky">
215
+ <h3 class="nh-kanban-col__title">In review <span class="nh-kanban-col__count">(2)</span></h3>
216
+ <button type="button" class="nh-btn nh-btn--ghost" aria-label="Column menu">⋯</button>
217
+ </div>
218
+ <div class="nh-kanban-col__body">
219
+ <article class="nh-card nh-card--interactive">
220
+ <h3 class="nh-card__title">Sample task in review</h3>
221
+ <p class="nh-card__body">Short description that clamps to two lines in the layout.</p>
222
+ <div class="nh-card__footer">
223
+ <div class="nh-ds-row">
224
+ <span class="nh-avatar-fallback">R</span>
225
+ <span class="nh-pill nh-pill--review">In review</span>
226
+ </div>
227
+ <span class="nh-card__meta">2h ago</span>
228
+ </div>
229
+ </article>
230
+ </div>
231
+ </div>
232
+ <div class="nh-kanban-col nh-kanban-col--success">
233
+ <div class="nh-kanban-col__head nh-kanban-col__head--sticky">
234
+ <h3 class="nh-kanban-col__title">Done <span class="nh-kanban-col__count">(36)</span></h3>
235
+ <button type="button" class="nh-btn nh-btn--ghost" aria-label="Column menu">⋯</button>
236
+ </div>
237
+ <div class="nh-kanban-col__body">
238
+ <article class="nh-card nh-card--success nh-card--interactive">
239
+ <div class="nh-done-row">
240
+ <span class="nh-done-row__icon" aria-hidden="true">✓</span>
241
+ <h3 class="nh-done-row__title">Shipped: dashboard design tokens</h3>
242
+ </div>
243
+ <div class="nh-card__footer">
244
+ <div class="nh-ds-row">
245
+ <span class="nh-avatar-fallback nh-avatar-fallback--success">D</span>
246
+ <span class="nh-pill nh-pill--done">Done</span>
247
+ </div>
248
+ <span class="nh-card__meta">yesterday</span>
249
+ </div>
250
+ </article>
251
+ </div>
252
+ </div>
253
+ </div>
254
+
255
+ <p style="font-size: 12px; color: var(--nh-text-secondary); margin-top: var(--nh-space-6); max-width: 720px;">
256
+ CSS variables live on <code style="color: var(--nh-text-primary);">:root</code> (prefix <code style="color: var(--nh-text-primary);">--nh-</code>).
257
+ Components use the <code style="color: var(--nh-text-primary);">nh-</code> prefix. Source: <code style="color: var(--nh-text-primary);">design-system.css</code>.
258
+ The live dashboard links the same file and aliases its legacy tokens to <code style="color: var(--nh-text-primary);">--nh-*</code> so the UI stays on one palette.
259
+ </p>
260
+ </div>
261
+ </div>
262
+ </div>
263
+ </body>
264
+ </html>
package/lib/agents.js CHANGED
@@ -36,7 +36,8 @@ function isPidAlive(pid, lastActivity) {
36
36
  return alive;
37
37
  }
38
38
 
39
- function getAgents() {
39
+ function getAgents(force = false) {
40
+ if (force) invalidateCache('agents');
40
41
  return cachedRead('agents', () => {
41
42
  if (!fs.existsSync(AGENTS_FILE)) return {};
42
43
  let agents;
@@ -50,6 +51,7 @@ function getAgents() {
50
51
  const hb = JSON.parse(fs.readFileSync(path.join(DATA_DIR, f), 'utf8'));
51
52
  if (hb.last_activity) agents[name].last_activity = hb.last_activity;
52
53
  if (hb.pid) agents[name].pid = hb.pid;
54
+ if (hb.listen_history) agents[name].listen_history = hb.listen_history;
53
55
  } catch {}
54
56
  }
55
57
  }
@@ -68,13 +70,25 @@ function saveAgents(agents) {
68
70
 
69
71
  function heartbeatFile(name) { return path.join(DATA_DIR, `heartbeat-${name}.json`); }
70
72
 
71
- function touchHeartbeat(name) {
73
+ function touchHeartbeat(name, type = null) {
72
74
  if (!name) return;
73
75
  try {
74
- fs.writeFileSync(heartbeatFile(name), JSON.stringify({
75
- last_activity: new Date().toISOString(),
76
- pid: process.pid,
77
- }));
76
+ const file = heartbeatFile(name);
77
+ let data = { last_activity: new Date().toISOString(), pid: process.pid, listen_history: [] };
78
+ if (fs.existsSync(file)) {
79
+ try { data = JSON.parse(fs.readFileSync(file, 'utf8')); } catch {}
80
+ }
81
+ data.last_activity = new Date().toISOString();
82
+ data.pid = process.pid;
83
+
84
+ if (type === 'listen' || type === true) {
85
+ if (!data.listen_history) data.listen_history = [];
86
+ const nowTs = Date.now();
87
+ data.listen_history.unshift(nowTs);
88
+ data.listen_history = data.listen_history.slice(0, 10);
89
+ data.last_listen_call = new Date(nowTs).toISOString();
90
+ }
91
+ fs.writeFileSync(file, JSON.stringify(data));
78
92
  } catch {}
79
93
  }
80
94