@yemi33/minions 0.1.504 → 0.1.506

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.506 (2026-04-07)
4
+
5
+ ### Features
6
+ - abort and retrigger buttons for active pipeline runs
7
+
8
+ ### Fixes
9
+ - bug report shows feedback inside modal, not hidden toast
10
+
3
11
  ## 0.1.504 (2026-04-07)
4
12
 
5
13
  ### Features
@@ -177,7 +177,10 @@ function openPipelineDetail(id) {
177
177
  html += '<div style="display:flex;justify-content:space-between;align-items:center">' +
178
178
  '<span style="font-size:10px;color:var(--muted)">' + (p.trigger?.cron ? escHtml(_cronToHuman(p.trigger.cron)) + ' <span style="opacity:0.6">(' + escHtml(p.trigger.cron) + ', ' + escHtml(Intl.DateTimeFormat().resolvedOptions().timeZone) + ')</span>' : 'Manual trigger') + '</span>' +
179
179
  '<div style="display:flex;gap:6px">' +
180
- (activeRun ? '' : '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_triggerPipeline(\'' + escHtml(id) + '\',this)">Run Now</button>') +
180
+ (activeRun
181
+ ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_abortPipeline(\'' + escHtml(id) + '\',this)">Abort</button>' +
182
+ '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--yellow);border-color:var(--yellow)" onclick="_retriggerPipeline(\'' + escHtml(id) + '\',this)">Retrigger</button>'
183
+ : '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="_triggerPipeline(\'' + escHtml(id) + '\',this)">Run Now</button>') +
181
184
  '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--blue);border-color:var(--blue)" onclick="openEditPipelineModal(\'' + escHtml(id) + '\')">Edit</button>' +
182
185
  '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px" onclick="_togglePipelineEnabled(\'' + escHtml(id) + '\',' + !p.enabled + ',this)">' + (p.enabled !== false ? 'Disable' : 'Enable') + '</button>' +
183
186
  '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red);border-color:var(--red)" onclick="_deletePipelineConfirm(\'' + escHtml(id) + '\')">Delete</button>' +
@@ -247,6 +250,33 @@ async function _triggerPipeline(id, btn) {
247
250
  } catch (e) { if (btn) { btn.textContent = 'Run Now'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } alert('Error: ' + e.message); }
248
251
  }
249
252
 
253
+ async function _abortPipeline(id, btn) {
254
+ if (!confirm('Abort the active run for "' + id + '"?')) return;
255
+ if (btn) { btn.textContent = 'Aborting...'; btn.style.pointerEvents = 'none'; btn.style.opacity = '0.6'; }
256
+ try {
257
+ var res = await fetch('/api/pipelines/abort', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: id }) });
258
+ if (res.ok) {
259
+ showToast('cmd-toast', 'Pipeline run aborted', true);
260
+ if (btn) { btn.textContent = '\u2713 Aborted'; btn.style.color = 'var(--red)'; }
261
+ setTimeout(function() { openPipelineDetail(id); }, 1500);
262
+ } else { var d = await res.json().catch(function() { return {}; }); alert('Abort failed: ' + (d.error || 'unknown')); if (btn) { btn.textContent = 'Abort'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } }
263
+ } catch (e) { alert('Error: ' + e.message); if (btn) { btn.textContent = 'Abort'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } }
264
+ }
265
+
266
+ async function _retriggerPipeline(id, btn) {
267
+ if (!confirm('Abort current run and start a fresh one for "' + id + '"?')) return;
268
+ if (btn) { btn.textContent = 'Retriggering...'; btn.style.pointerEvents = 'none'; btn.style.opacity = '0.6'; }
269
+ try {
270
+ var res = await fetch('/api/pipelines/retrigger', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: id }) });
271
+ var d = await res.json();
272
+ if (res.ok) {
273
+ showToast('cmd-toast', 'Pipeline retriggered: ' + (d.runId || ''), true);
274
+ if (btn) { btn.textContent = '\u2713 Retriggered'; btn.style.color = 'var(--green)'; }
275
+ setTimeout(function() { openPipelineDetail(id); }, 1500);
276
+ } else { alert('Retrigger failed: ' + (d.error || 'unknown')); if (btn) { btn.textContent = 'Retrigger'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } }
277
+ } catch (e) { alert('Error: ' + e.message); if (btn) { btn.textContent = 'Retrigger'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } }
278
+ }
279
+
250
280
  async function _togglePipelineEnabled(id, enabled, btn) {
251
281
  if (btn) { btn.textContent = enabled ? 'Enabling...' : 'Disabling...'; btn.style.pointerEvents = 'none'; }
252
282
  try {
@@ -220,8 +220,11 @@ async function submitBugReport() {
220
220
  var title = document.getElementById('bug-title')?.value?.trim();
221
221
  var desc = document.getElementById('bug-desc')?.value?.trim();
222
222
  if (!title) { alert('Title is required'); return; }
223
- try { closeModal(); } catch {}
224
- showToast('cmd-toast', 'Filing bug...', true);
223
+
224
+ // Show progress inside the modal
225
+ var btn = document.querySelector('#modal button[onclick="submitBugReport()"]');
226
+ if (btn) { btn.disabled = true; btn.textContent = 'Filing...'; }
227
+
225
228
  try {
226
229
  var res = await fetch('/api/issues/create', {
227
230
  method: 'POST', headers: { 'Content-Type': 'application/json' },
@@ -229,12 +232,27 @@ async function submitBugReport() {
229
232
  });
230
233
  var d = await res.json();
231
234
  if (!res.ok) throw new Error(d.error || 'Failed');
232
- if (d.url) {
233
- showToast('cmd-toast', 'Bug filed <a href="' + d.url + '" target="_blank" style="color:var(--blue)">view issue</a>', true);
234
- } else {
235
- showToast('cmd-toast', 'Bug filed', true);
235
+
236
+ // Show success inside the modal
237
+ document.getElementById('modal-body').innerHTML =
238
+ '<div style="padding:24px;text-align:center">' +
239
+ '<div style="font-size:32px;margin-bottom:12px">&#128027;</div>' +
240
+ '<div style="color:var(--green);font-weight:600;margin-bottom:8px">Bug filed!</div>' +
241
+ (d.url ? '<a href="' + escHtml(d.url) + '" target="_blank" style="color:var(--blue);font-size:13px">View issue on GitHub</a>' : '<span style="color:var(--muted);font-size:12px">Issue created on yemi33/minions</span>') +
242
+ '<div style="margin-top:16px"><button onclick="closeModal()" style="padding:6px 16px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;color:var(--text)">Close</button></div>' +
243
+ '</div>';
244
+ } catch (e) {
245
+ // Show error inside the modal — let user retry
246
+ if (btn) { btn.disabled = false; btn.textContent = 'File Bug'; }
247
+ var errDiv = document.getElementById('bug-error');
248
+ if (!errDiv) {
249
+ errDiv = document.createElement('div');
250
+ errDiv.id = 'bug-error';
251
+ errDiv.style.cssText = 'color:var(--red);font-size:12px;padding:8px;background:rgba(248,81,73,0.1);border-radius:4px';
252
+ btn?.parentElement?.parentElement?.appendChild(errDiv);
236
253
  }
237
- } catch (e) { showToast('cmd-toast', 'Error: ' + e.message, false); }
254
+ errDiv.textContent = 'Error: ' + e.message;
255
+ }
238
256
  }
239
257
 
240
258
  window.MinionsUtils = { wakeEngine, escHtml, renderMd, normalizePlanFile, timeAgo, statusColor, llmCopyBtn, copyLlmText, openBugReport, submitBugReport };
package/dashboard.js CHANGED
@@ -4045,6 +4045,30 @@ What would you like to discuss or change? When you're happy, say "approve" and I
4045
4045
  return jsonReply(res, 200, { ok: true });
4046
4046
  }},
4047
4047
 
4048
+ { method: 'POST', path: '/api/pipelines/abort', desc: 'Abort an active pipeline run', params: 'id', handler: async (req, res) => {
4049
+ const body = await readBody(req);
4050
+ if (!body.id) return jsonReply(res, 400, { error: 'id required' });
4051
+ const { getActiveRun, completeRun } = require('./engine/pipeline');
4052
+ const run = getActiveRun(body.id);
4053
+ if (!run) return jsonReply(res, 404, { error: 'No active run to abort' });
4054
+ completeRun(body.id, run.runId, 'failed');
4055
+ invalidateStatusCache();
4056
+ return jsonReply(res, 200, { ok: true, runId: run.runId });
4057
+ }},
4058
+ { method: 'POST', path: '/api/pipelines/retrigger', desc: 'Abort active run (if any) and start a new one', params: 'id', handler: async (req, res) => {
4059
+ const body = await readBody(req);
4060
+ if (!body.id) return jsonReply(res, 400, { error: 'id required' });
4061
+ const pipeline = require('./engine/pipeline');
4062
+ const run = pipeline.getActiveRun(body.id);
4063
+ if (run) pipeline.completeRun(body.id, run.runId, 'failed');
4064
+ const pipelines = pipeline.getPipelines();
4065
+ const def = pipelines.find(p => p.id === body.id);
4066
+ if (!def) return jsonReply(res, 404, { error: 'Pipeline not found' });
4067
+ const newRun = pipeline.startRun(body.id, def);
4068
+ invalidateStatusCache();
4069
+ return jsonReply(res, 200, { ok: true, runId: newRun?.runId });
4070
+ }},
4071
+
4048
4072
  // Meetings
4049
4073
  { method: 'POST', path: '/api/meetings', desc: 'Create a team meeting', params: 'title, agenda, participants[]', handler: async (req, res) => {
4050
4074
  const body = await readBody(req);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.504",
3
+ "version": "0.1.506",
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"