@yemi33/minions 0.1.1565 → 0.1.1567

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.1567 (2026-04-27)
4
+
5
+ ### Other
6
+ - Clarify PRD delete toast
7
+
3
8
  ## 0.1.1565 (2026-04-27)
4
9
 
5
10
  ### Other
@@ -574,8 +574,12 @@ async function planApprove(file, btn) {
574
574
 
575
575
  async function planDelete(file) {
576
576
  _stopPlanPoll();
577
- if (!confirm('Delete plan "' + file + '"? This cannot be undone.')) return;
578
- showToast('cmd-toast', 'Plan deleted', true);
577
+ var isPrd = file.endsWith('.json');
578
+ var confirmMsg = isPrd
579
+ ? 'Delete PRD "' + file + '"? This cannot be undone. The source plan will be kept.'
580
+ : 'Delete plan "' + file + '"? This cannot be undone.';
581
+ if (!confirm(confirmMsg)) return;
582
+ showToast('cmd-toast', isPrd ? 'PRD deleted' : 'Plan deleted', true);
579
583
  markDeleted('plan:' + file);
580
584
  try { closeModal(); } catch { /* may not be open */ }
581
585
  if (window._lastPlans) renderPlans(window._lastPlans);
@@ -593,7 +597,11 @@ async function planDelete(file) {
593
597
  showToast('cmd-toast', 'Delete failed: ' + (d.error || 'unknown'), false);
594
598
  refresh(); // revert optimistic
595
599
  }
596
- } catch (e) { clearDeleted('plan:' + file); showToast('cmd-toast', 'Error: ' + e.message, false); refresh(); }
600
+ } catch (e) {
601
+ clearDeleted('plan:' + file);
602
+ showToast('cmd-toast', 'Error: ' + e.message, false);
603
+ refresh();
604
+ }
597
605
  }
598
606
 
599
607
  async function planArchive(file, btn) {
package/dashboard.js CHANGED
@@ -5521,71 +5521,86 @@ What would you like to discuss or change? When you're happy, say "approve" and I
5521
5521
  }
5522
5522
  });
5523
5523
 
5524
- server.listen(PORT, '127.0.0.1', () => {
5525
- console.log(`\n Minions Mission Control`);
5526
- console.log(` -----------------------------------`);
5527
- console.log(` http://localhost:${PORT}`);
5528
- console.log(`\n Watching:`);
5529
- console.log(` Minions dir: ${MINIONS_DIR}`);
5530
- console.log(` Projects: ${PROJECTS.map(p => `${p.name} (${p.localPath})`).join(', ')}`);
5531
- console.log(`\n Auto-refreshes every 4s. Ctrl+C to stop.\n`);
5532
-
5533
- const { exec } = require('child_process');
5534
- try {
5535
- if (process.platform === 'win32') {
5536
- exec(`start "" "http://localhost:${PORT}"`);
5537
- } else if (process.platform === 'darwin') {
5538
- exec(`open http://localhost:${PORT}`);
5539
- } else {
5540
- exec(`xdg-open http://localhost:${PORT}`);
5541
- }
5542
- } catch (e) {
5543
- console.log(` Could not auto-open browser: ${e.message}`);
5544
- console.log(` Please open http://localhost:${PORT} manually.`);
5545
- }
5524
+ // Exported for testing — pure helpers with no hidden side effects.
5525
+ // Production entry points use the closures directly; tests import via require('./dashboard').
5526
+ module.exports = {
5527
+ getMcpServers,
5528
+ _filterCcTabSessions,
5529
+ _getVersionCheckInterval,
5530
+ _parseWatchInterval,
5531
+ parsePinnedEntries,
5532
+ };
5546
5533
 
5547
- // ─── Engine Watchdog ─────────────────────────────────────────────────────
5548
- // Every 30s, check if engine PID is alive. If dead but control.json says
5549
- // running, auto-restart it. Prevents silent engine death.
5550
- const { execSync } = require('child_process');
5551
- setInterval(() => {
5534
+ // Start the HTTP server only when run directly (node dashboard.js).
5535
+ // When required as a module (e.g. by unit tests), skip the listen/watchdog/signal
5536
+ // handlers so tests can import exported helpers without binding to port 7331.
5537
+ if (require.main === module) {
5538
+ server.listen(PORT, '127.0.0.1', () => {
5539
+ console.log(`\n Minions Mission Control`);
5540
+ console.log(` -----------------------------------`);
5541
+ console.log(` http://localhost:${PORT}`);
5542
+ console.log(`\n Watching:`);
5543
+ console.log(` Minions dir: ${MINIONS_DIR}`);
5544
+ console.log(` Projects: ${PROJECTS.map(p => `${p.name} (${p.localPath})`).join(', ')}`);
5545
+ console.log(`\n Auto-refreshes every 4s. Ctrl+C to stop.\n`);
5546
+
5547
+ const { exec } = require('child_process');
5552
5548
  try {
5553
- const control = getEngineState();
5554
- if (control.state !== 'running' || !control.pid) return;
5549
+ if (process.platform === 'win32') {
5550
+ exec(`start "" "http://localhost:${PORT}"`);
5551
+ } else if (process.platform === 'darwin') {
5552
+ exec(`open http://localhost:${PORT}`);
5553
+ } else {
5554
+ exec(`xdg-open http://localhost:${PORT}`);
5555
+ }
5556
+ } catch (e) {
5557
+ console.log(` Could not auto-open browser: ${e.message}`);
5558
+ console.log(` Please open http://localhost:${PORT} manually.`);
5559
+ }
5555
5560
 
5556
- // Check if PID is alive
5557
- let alive = false;
5561
+ // ─── Engine Watchdog ─────────────────────────────────────────────────────
5562
+ // Every 30s, check if engine PID is alive. If dead but control.json says
5563
+ // running, auto-restart it. Prevents silent engine death.
5564
+ const { execSync } = require('child_process');
5565
+ setInterval(() => {
5558
5566
  try {
5559
- if (process.platform === 'win32') {
5560
- const out = execSync(`tasklist /FI "PID eq ${control.pid}" /NH`, { encoding: 'utf8', timeout: 3000, windowsHide: true });
5561
- alive = out.includes(String(control.pid));
5562
- } else {
5563
- process.kill(control.pid, 0); // signal 0 = check existence
5564
- alive = true;
5565
- }
5566
- } catch { alive = false; }
5567
+ const control = getEngineState();
5568
+ if (control.state !== 'running' || !control.pid) return;
5569
+
5570
+ // Check if PID is alive
5571
+ let alive = false;
5572
+ try {
5573
+ if (process.platform === 'win32') {
5574
+ const out = execSync(`tasklist /FI "PID eq ${control.pid}" /NH`, { encoding: 'utf8', timeout: 3000, windowsHide: true });
5575
+ alive = out.includes(String(control.pid));
5576
+ } else {
5577
+ process.kill(control.pid, 0); // signal 0 = check existence
5578
+ alive = true;
5579
+ }
5580
+ } catch { alive = false; }
5567
5581
 
5568
- if (!alive) {
5569
- console.log(`[watchdog] Engine PID ${control.pid} is dead — auto-restarting...`);
5570
- restartEngine();
5582
+ if (!alive) {
5583
+ console.log(`[watchdog] Engine PID ${control.pid} is dead — auto-restarting...`);
5584
+ restartEngine();
5585
+ }
5586
+ } catch (e) {
5587
+ console.error(`[watchdog] Error: ${e.message}`);
5571
5588
  }
5572
- } catch (e) {
5573
- console.error(`[watchdog] Error: ${e.message}`);
5574
- }
5575
- }, 30000);
5576
- console.log(` Engine watchdog: active (checks every 30s)`);
5577
- });
5589
+ }, 30000);
5590
+ console.log(` Engine watchdog: active (checks every 30s)`);
5591
+ });
5578
5592
 
5579
- server.on('error', e => {
5580
- if (e.code === 'EADDRINUSE') {
5581
- console.error(`\n Port ${PORT} already in use. Kill the existing process or change PORT.\n`);
5582
- } else {
5583
- console.error(e);
5584
- }
5585
- process.exit(1);
5586
- });
5593
+ server.on('error', e => {
5594
+ if (e.code === 'EADDRINUSE') {
5595
+ console.error(`\n Port ${PORT} already in use. Kill the existing process or change PORT.\n`);
5596
+ } else {
5597
+ console.error(e);
5598
+ }
5599
+ process.exit(1);
5600
+ });
5587
5601
 
5588
- // ── Graceful shutdown: flush debounced writes ──────────────────────────────
5589
- server.on('close', () => flushPendingDocSessions());
5590
- process.on('SIGTERM', () => { flushPendingDocSessions(); process.exit(0); });
5591
- process.on('SIGINT', () => { flushPendingDocSessions(); process.exit(0); });
5602
+ // ── Graceful shutdown: flush debounced writes ──────────────────────────────
5603
+ server.on('close', () => flushPendingDocSessions());
5604
+ process.on('SIGTERM', () => { flushPendingDocSessions(); process.exit(0); });
5605
+ process.on('SIGINT', () => { flushPendingDocSessions(); process.exit(0); });
5606
+ }
package/engine/ado.js CHANGED
@@ -430,6 +430,12 @@ async function pollPrStatus(config) {
430
430
  if (newReviewStatus === 'approved') {
431
431
  delete pr._reviewFixCycles;
432
432
  delete pr._evalEscalated;
433
+ // Teams notification for PR approval — non-blocking, edge-triggered (only on transition)
434
+ try {
435
+ const teams = require('./teams');
436
+ const prFilePath = shared.projectPrPath(project);
437
+ teams.teamsNotifyPrEvent(pr, 'pr-approved', project, prFilePath).catch(() => {});
438
+ } catch {}
433
439
  }
434
440
  }
435
441
 
package/engine/github.js CHANGED
@@ -414,6 +414,12 @@ async function pollPrStatus(config) {
414
414
  if (newReviewStatus === 'approved') {
415
415
  delete pr._reviewFixCycles;
416
416
  delete pr._evalEscalated;
417
+ // Teams notification for PR approval — non-blocking, edge-triggered (only on transition)
418
+ try {
419
+ const teams = require('./teams');
420
+ const prFilePath = shared.projectPrPath(project);
421
+ teams.teamsNotifyPrEvent(pr, 'pr-approved', project, prFilePath).catch(() => {});
422
+ } catch {}
417
423
  }
418
424
  }
419
425
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1565",
3
+ "version": "0.1.1567",
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"