@yemi33/minions 0.1.1584 → 0.1.1586

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,8 +1,10 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1584 (2026-04-28)
3
+ ## 0.1.1586 (2026-04-28)
4
4
 
5
5
  ### Fixes
6
+ - stop URL regex at backslash to prevent JSONL escape leakage
7
+ - optimistic UI for planApprove cascades to linked PRD
6
8
  - stack chain-of-thought above progress block (was side-by-side)
7
9
 
8
10
  ### Other
@@ -559,6 +559,32 @@ async function planView(file) {
559
559
  async function planApprove(file, btn) {
560
560
  if (btn) { btn.dataset.origText = btn.textContent; btn.textContent = 'Approving...'; btn.style.pointerEvents = 'none'; btn.style.opacity = '0.6'; }
561
561
  showToast('cmd-toast', 'Plan approved — work will begin on next engine tick', true);
562
+
563
+ // Optimistic UI: mutate cached state and re-render so both the plan card and
564
+ // PRD view reflect 'approved' immediately. The .md card's display status
565
+ // follows the linked PRD's status via lookup in renderPlanCard, so updating
566
+ // the PRD entry covers both. Refresh after fetch reconciles with truth.
567
+ const isPrd = typeof file === 'string' && file.endsWith('.json');
568
+ if (Array.isArray(window._lastPlans)) {
569
+ for (const p of window._lastPlans) {
570
+ if (p.file === file) {
571
+ p.status = 'approved';
572
+ p.planStale = false;
573
+ delete p.pausedAt;
574
+ }
575
+ }
576
+ try { renderPlans(window._lastPlans); } catch { /* render is best-effort */ }
577
+ }
578
+ if (isPrd && window._lastStatus?.prdProgress?.items) {
579
+ for (const item of window._lastStatus.prdProgress.items) {
580
+ if (item.source === file) {
581
+ item.planStatus = 'approved';
582
+ item.planStale = false;
583
+ }
584
+ }
585
+ if (typeof rerenderPrdFromCache === 'function') rerenderPrdFromCache();
586
+ }
587
+
562
588
  try {
563
589
  const res = await fetch('/api/plans/approve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file }) });
564
590
  if (res.ok) {
@@ -568,8 +594,14 @@ async function planApprove(file, btn) {
568
594
  if (btn) { btn.textContent = btn.dataset.origText || 'Approve'; btn.style.pointerEvents = ''; btn.style.opacity = ''; }
569
595
  const d = await res.json().catch(() => ({}));
570
596
  showToast('cmd-toast', 'Approve failed: ' + (d.error || 'unknown'), false);
597
+ // Refresh to revert optimistic state from server truth
598
+ refresh();
571
599
  }
572
- } catch (e) { if (btn) { btn.textContent = btn.dataset.origText || 'Approve'; btn.style.pointerEvents = ''; btn.style.opacity = ''; } showToast('cmd-toast', 'Error: ' + e.message, false); }
600
+ } catch (e) {
601
+ if (btn) { btn.textContent = btn.dataset.origText || 'Approve'; btn.style.pointerEvents = ''; btn.style.opacity = ''; }
602
+ showToast('cmd-toast', 'Error: ' + e.message, false);
603
+ refresh();
604
+ }
573
605
  }
574
606
 
575
607
  async function planDelete(file) {
@@ -771,9 +771,11 @@ function syncPrsFromOutput(output, agentId, meta, config) {
771
771
 
772
772
  // Extract PR URL directly from agent output — no manual construction
773
773
  function extractPrUrl(prId) {
774
- const ghMatch = output.match(new RegExp(`https?://github\\.com/[^\\s"'\\)\\]]*?/pull/${prId}(?:[^\\s"'\\)\\]]*)`, 'i'));
774
+ // Stop at backslash in addition to whitespace/quotes — raw JSONL encodes newlines as \n (literal
775
+ // backslash-n), so without this the regex would capture e.g. "pull/1804\n/usr/bin/bash".
776
+ const ghMatch = output.match(new RegExp(`https?://github\\.com/[^\\s"'\\)\\]\\\\]*?/pull/${prId}(?:[^\\s"'\\)\\]\\\\]*)`, 'i'));
775
777
  if (ghMatch) return ghMatch[0].replace(/[.,;:]+$/, '');
776
- const adoMatch = output.match(new RegExp(`https?://(?:dev\\.azure\\.com|[^/]+\\.visualstudio\\.com)[^\\s"'\\)\\]]*?pullrequest/${prId}(?:[^\\s"'\\)\\]]*)`, 'i'));
778
+ const adoMatch = output.match(new RegExp(`https?://(?:dev\\.azure\\.com|[^/]+\\.visualstudio\\.com)[^\\s"'\\)\\]\\\\]*?pullrequest/${prId}(?:[^\\s"'\\)\\]\\\\]*)`, 'i'));
777
779
  if (adoMatch) return adoMatch[0].replace(/[.,;:]+$/, '');
778
780
  return '';
779
781
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1584",
3
+ "version": "0.1.1586",
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"