@yemi33/minions 0.1.680 → 0.1.681

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.681 (2026-04-09)
4
+
5
+ ### Features
6
+ - horizontal node chain pipeline visualization (TDD)
7
+
3
8
  ## 0.1.678 (2026-04-09)
4
9
 
5
10
  ### Fixes
@@ -176,6 +176,81 @@ function _buildProgressBar(stages, run, options) {
176
176
  '</div>';
177
177
  }
178
178
 
179
+ var _nodeIcons = { task: '\u2699', meeting: '\uD83D\uDCAC', plan: '\uD83D\uDCCB', 'merge-prs': '\uD83D\uDD04', condition: '\u2753', wait: '\u23F8', parallel: '\u2693', schedule: '\u23F0', api: '\uD83C\uDF10' };
180
+
181
+ function _buildNodeChain(stages, run, options) {
182
+ var compact = options && options.compact;
183
+ var pipeline = options && options.pipeline;
184
+ var html = '<div class="pl-node-chain">';
185
+
186
+ for (var i = 0; i < stages.length; i++) {
187
+ var s = stages[i];
188
+ var stageRun = run?.stages?.[s.id];
189
+ var st = stageRun?.status || 'pending';
190
+ var cls = st === 'completed' ? 'complete' : st === 'running' ? 'running' : st === 'failed' ? 'failed' : st === 'waiting-human' ? 'waiting' : 'pending';
191
+ var icon = _nodeIcons[s.type] || '\u2699';
192
+ var isCondition = s.type === 'condition';
193
+ var isWait = s.type === 'wait';
194
+
195
+ // Arrow before node (except first)
196
+ if (i > 0) html += '<div class="pl-node-arrow">\u2192</div>';
197
+
198
+ html += '<div class="pl-node">';
199
+ html += '<div class="pl-node-box ' + cls + (isCondition ? ' condition' : '') + '" title="' + escHtml(s.id) + ': ' + st + '">';
200
+ html += icon + ' ' + escHtml(s.title || s.id);
201
+ if (isWait && s.duration) html += ' ' + escHtml(s.duration);
202
+ html += '</div>';
203
+
204
+ // Meta line (agent, timing) — skip in compact mode
205
+ if (!compact) {
206
+ var meta = [];
207
+ var agent = stageRun?.agent || s.agent;
208
+ if (agent) meta.push(escHtml(agent));
209
+ if (st === 'completed' && stageRun?.completedAt) meta.push(timeSinceStr(new Date(stageRun.completedAt)));
210
+ if (st === 'running' && stageRun?.startedAt) meta.push(timeSinceStr(new Date(stageRun.startedAt)));
211
+ // Artifact counts
212
+ var arts = stageRun?.artifacts || {};
213
+ var artCounts = [];
214
+ if (arts.workItems?.length) artCounts.push(arts.workItems.length + ' WI');
215
+ if (arts.prs?.length) artCounts.push(arts.prs.length + ' PR');
216
+ if (arts.notes?.length) artCounts.push(arts.notes.length + ' notes');
217
+ if (artCounts.length) meta.push(artCounts.join(', '));
218
+ if (meta.length) html += '<div class="pl-node-meta">' + meta.join(' \u00b7 ') + '</div>';
219
+ }
220
+
221
+ // Condition fork labels
222
+ if (isCondition) {
223
+ html += '<div class="pl-node-meta" style="font-style:italic">';
224
+ if (s.onMet) html += '\u2714 ' + escHtml(s.onMet);
225
+ if (s.onMet && s.onUnmet) html += ' / ';
226
+ if (s.onUnmet) html += '\u2718 ' + escHtml(s.onUnmet);
227
+ html += '</div>';
228
+ }
229
+
230
+ html += '</div>';
231
+ }
232
+
233
+ // Stop/exit condition terminal node
234
+ var stopWhen = pipeline?.stopWhen;
235
+ if (stopWhen) {
236
+ html += '<div class="pl-node-arrow">\u2192</div>';
237
+ html += '<div class="pl-node"><div class="pl-node-box pl-node-stop">\u23F9 Stop</div>';
238
+ html += '<div class="pl-node-meta">' + escHtml(stopWhen) + '</div></div>';
239
+ }
240
+
241
+ html += '</div>';
242
+
243
+ // Loop indicator
244
+ if (pipeline?.trigger?.cron) {
245
+ var runCount = (pipeline.runs || []).length;
246
+ html += '<div class="pl-node-loop">\u21BA Loop (' + escHtml(_cronToHuman(pipeline.trigger.cron)) + ')';
247
+ if (runCount > 0) html += ' \u00b7 Run ' + runCount;
248
+ html += '</div>';
249
+ }
250
+
251
+ return html;
252
+ }
253
+
179
254
  function renderPipelines(pipelines) {
180
255
  _pipelinesData = pipelines || [];
181
256
  const el = document.getElementById('pipelines-content');
@@ -207,7 +282,7 @@ function renderPipelines(pipelines) {
207
282
  var progressHtml = '';
208
283
  var displayRun = activeRun || lastRun;
209
284
  if (displayRun && (p.stages || []).length > 0) {
210
- progressHtml = _buildProgressBar(p.stages || [], displayRun);
285
+ progressHtml = _buildNodeChain(p.stages || [], displayRun, { compact: true, pipeline: p });
211
286
  }
212
287
 
213
288
  // Monitored resources (pipeline-level + stage-level, compact on card)
@@ -256,7 +331,7 @@ function openPipelineDetail(id) {
256
331
  // Stage detail with progress bar
257
332
  var detailRun = activeRun || (p.runs || []).slice(-1)[0];
258
333
  if (detailRun && (p.stages || []).length > 0) {
259
- html += _buildProgressBar(p.stages || [], detailRun, { height: '8px', detailLabel: true });
334
+ html += _buildNodeChain(p.stages || [], detailRun, { compact: false, pipeline: p });
260
335
  }
261
336
  // Pipeline-level monitored resources (full view in detail)
262
337
  var pipelineResources = _collectMonitoredResources(p);
@@ -192,6 +192,19 @@
192
192
  .pl-prog-seg.pending { background: transparent; }
193
193
  @keyframes plSegPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
194
194
  .pl-progress-label { display: flex; gap: 8px; align-items: center; margin-top: 4px; font-size: 10px; }
195
+ .pl-node-chain { display: flex; align-items: flex-start; gap: 0; overflow-x: auto; padding: 8px 0; }
196
+ .pl-node { display: flex; flex-direction: column; align-items: center; min-width: 80px; max-width: 130px; }
197
+ .pl-node-box { padding: 5px 10px; border-radius: 8px; border: 2px solid var(--border); background: var(--surface2); text-align: center; font-size: 11px; transition: border-color 0.2s; white-space: nowrap; }
198
+ .pl-node-box.complete { border-color: var(--green); background: rgba(63,185,80,0.08); }
199
+ .pl-node-box.running { border-color: var(--blue); animation: plSegPulse 1.5s ease-in-out infinite; }
200
+ .pl-node-box.failed { border-color: var(--red); background: rgba(248,81,73,0.08); }
201
+ .pl-node-box.waiting { border-color: var(--yellow); }
202
+ .pl-node-box.pending { border-color: var(--border); opacity: 0.6; }
203
+ .pl-node-box.condition { border-style: dashed; }
204
+ .pl-node-box.pl-node-stop { border-style: dotted; border-color: var(--muted); opacity: 0.7; }
205
+ .pl-node-arrow { display: flex; align-items: center; padding: 0 2px; color: var(--muted); font-size: 12px; flex-shrink: 0; margin-top: 8px; }
206
+ .pl-node-meta { font-size: 9px; color: var(--muted); margin-top: 2px; text-align: center; max-width: 120px; overflow: hidden; text-overflow: ellipsis; }
207
+ .pl-node-loop { font-size: 10px; color: var(--muted); margin-top: 6px; display: flex; align-items: center; gap: 6px; }
195
208
  .prd-items-list { display: flex; flex-direction: column; gap: 3px; max-height: 400px; overflow-y: auto; padding: 0 8px; }
196
209
  .prd-item-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-radius: var(--radius-sm); font-size: var(--text-base); background: var(--surface2); border: 1px solid var(--border); border-left: 3px solid var(--border); }
197
210
  .prd-item-row.st-done { border-left-color: var(--green); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.680",
3
+ "version": "0.1.681",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"