@yemi33/minions 0.1.913 → 0.1.914

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,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.913 (2026-04-13)
3
+ ## 0.1.914 (2026-04-13)
4
4
 
5
5
  ### Features
6
6
  - fix dep re-merge failure on retry with existing commits (#977)
@@ -17,6 +17,8 @@
17
17
  - add red dot notification on CC tab when response completes (#934) (#946)
18
18
 
19
19
  ### Fixes
20
+ - prevent Create Plan from meeting saving doc-chat context bleed (#980)
21
+ - plan completion incorrectly overrides awaiting-approval status (#970) (#978)
20
22
  - CC queued messages sent to wrong tab after tab switch
21
23
  - pass sysPromptPath instead of steerPromptPath as system prompt in steering resume (#962)
22
24
  - PRD item display dispatched/in-progress status conflation (closes #950) (#955)
@@ -438,12 +438,19 @@ async function _createPlanFromMeeting(id, btn) {
438
438
  message: 'Create an actionable implementation plan from this meeting. Extract concrete action items from the conclusion and debates. For each item include: what to do, which files/areas to change, priority (high/medium/low), and estimated complexity (small/medium/large). Structure it as a plan ready for execution. Do NOT include preamble — start with the plan title.' + humanContext,
439
439
  document: meetingDoc,
440
440
  title: 'Meeting: ' + m.title,
441
+ freshSession: true,
441
442
  })
442
443
  });
443
444
  const genData = await genRes.json();
444
445
  if (!genRes.ok || !genData.ok) { resetBtn(); showToast('cmd-toast', 'Failed to generate plan: ' + (genData.error || 'unknown'), false); return; }
445
446
 
446
447
  const planContent = genData.answer || '';
448
+ // Guard: reject doc-chat meta-responses that aren't plan content
449
+ if (!planContent.trim() || !/^(#|\*\*|[-*] )/.test(planContent.trim())) {
450
+ resetBtn();
451
+ showToast('cmd-toast', 'Generated content does not look like a plan — try again', false);
452
+ return;
453
+ }
447
454
  const title = 'Meeting follow-up: ' + (m.title || id);
448
455
  const planRes = await fetch('/api/plans/create', {
449
456
  method: 'POST', headers: { 'Content-Type': 'application/json' },
@@ -81,14 +81,14 @@ function derivePlanStatus(prdFile, mdFile, prdJsonStatus, workItems) {
81
81
  if (prdJsonStatus === 'rejected') return 'rejected';
82
82
  if (prdJsonStatus === 'paused' && !allDone) return 'paused';
83
83
  if (prdJsonStatus === 'revision-requested') return 'revision-requested';
84
+ // PRD awaiting approval overrides WI-derived completion — new items may need materialization (#970)
85
+ if (prdJsonStatus === 'awaiting-approval') return 'awaiting-approval';
84
86
 
85
87
  // Derive from work item progress
86
88
  if (allDone && !hasActiveWork) return 'completed';
87
89
  if (hasActiveWork) return 'dispatched';
88
90
  if (hasPendingPrd) return 'converting';
89
91
  if (hasFailed && !hasActiveWork) return 'has-failures';
90
-
91
- if (prdJsonStatus === 'awaiting-approval' && implementWi.length === 0) return 'awaiting-approval';
92
92
  if (prdJsonStatus === 'approved' && implementWi.length === 0) return 'approved';
93
93
 
94
94
  // plan-to-prd conversion done but no implement items and PRD is gone — truly completed
package/dashboard.js CHANGED
@@ -783,13 +783,21 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
783
783
  }
784
784
 
785
785
  // Doc-specific wrapper — adds document context, parses ---DOCUMENT---
786
- async function ccDocCall({ message, document, title, filePath, selection, canEdit, isJson, model }) {
786
+ async function ccDocCall({ message, document, title, filePath, selection, canEdit, isJson, model, freshSession }) {
787
787
  const sessionKey = filePath || title;
788
788
  const docSlice = document.slice(0, 20000);
789
789
 
790
+ // freshSession: true → discard any prior session for this key so the call starts clean.
791
+ // Used by one-shot generation flows (e.g. Create Plan from meeting) that must not
792
+ // bleed context from earlier conversations.
793
+ if (freshSession && sessionKey) {
794
+ docSessions.delete(sessionKey);
795
+ // Skip persistDocSessions() here — the post-call cleanup below handles persistence.
796
+ }
797
+
790
798
  // Skip re-sending full document on session resume if content unchanged
791
799
  const docHash = require('crypto').createHash('md5').update(docSlice).digest('hex').slice(0, 8);
792
- const existing = resolveSession('doc', sessionKey);
800
+ const existing = freshSession ? null : resolveSession('doc', sessionKey);
793
801
  const docUnchanged = existing?.sessionId && existing._docHash === docHash;
794
802
 
795
803
  let docContext;
@@ -808,8 +816,14 @@ async function ccDocCall({ message, document, title, filePath, selection, canEdi
808
816
  skipStatePreamble: true,
809
817
  ...(model ? { model } : {}),
810
818
  });
811
- // Store doc hash for next call's unchanged check
812
- if (result.code === 0 && result.sessionId) {
819
+
820
+ if (freshSession && sessionKey) {
821
+ // One-shot call — discard the session ccCall just stored so it cannot
822
+ // bleed into future interactions under the same key.
823
+ docSessions.delete(sessionKey);
824
+ persistDocSessions();
825
+ } else if (result.code === 0 && result.sessionId) {
826
+ // Store doc hash for next call's unchanged check
813
827
  const session = resolveSession('doc', sessionKey);
814
828
  if (session) session._docHash = docHash;
815
829
  }
@@ -2843,6 +2857,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2843
2857
  message: body.message, document: currentContent, title: body.title,
2844
2858
  filePath: body.filePath, selection: body.selection, canEdit, isJson,
2845
2859
  model: body.model || undefined,
2860
+ freshSession: !!body.freshSession,
2846
2861
  });
2847
2862
 
2848
2863
  if (!content) return jsonReply(res, 200, { ok: true, answer, edited: false, actions });
@@ -4105,6 +4120,13 @@ What would you like to discuss or change? When you're happy, say "approve" and I
4105
4120
  const { title, content, project: projectName, meetingId } = body;
4106
4121
  if (!title || !content) return jsonReply(res, 400, { error: 'title and content required' });
4107
4122
 
4123
+ // Reject meta-responses that aren't actual plan content — e.g. doc-chat
4124
+ // summaries of prior conversations that reference existing plan files.
4125
+ const trimmed = content.trim();
4126
+ if (!/^#/.test(trimmed) && !/^\*\*/.test(trimmed) && !/^[-*] /.test(trimmed)) {
4127
+ return jsonReply(res, 400, { error: 'Plan content must start with a markdown heading (#), bold text (**), or a list item' });
4128
+ }
4129
+
4108
4130
  const plansDir = path.join(MINIONS_DIR, 'plans');
4109
4131
  if (!fs.existsSync(plansDir)) fs.mkdirSync(plansDir, { recursive: true });
4110
4132
  const slug = shared.slugify(title);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.913",
3
+ "version": "0.1.914",
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"