@yemi33/minions 0.1.1808 → 0.1.1809

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,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1808 (2026-05-08)
3
+ ## 0.1.1809 (2026-05-08)
4
+
5
+ ### Features
6
+ - add CC action intent fallback (#2234)
4
7
 
5
8
  ### Fixes
6
9
  - Plan-to-PRD conversion can override explicit plan project with contextual project (#2235)
@@ -567,7 +567,8 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
567
567
  }
568
568
  }
569
569
 
570
- async function ccSend() {
570
+ async function ccSend(options) {
571
+ var intentMetadata = options && options.intentMetadata ? options.intentMetadata : null;
571
572
  var input = document.getElementById('cc-input');
572
573
  var message = input.value.trim();
573
574
  if (!message) return;
@@ -580,11 +581,11 @@ async function ccSend() {
580
581
 
581
582
  // If this tab is already processing, queue the message
582
583
  if (tab._sending) {
583
- tab._queue.push(message);
584
+ tab._queue.push({ message: message, intentMetadata: intentMetadata });
584
585
  _renderQueueIndicator();
585
586
  return;
586
587
  }
587
- var wasAborted = await _ccDoSend(message, false, originTabId);
588
+ var wasAborted = await _ccDoSend(message, false, originTabId, intentMetadata);
588
589
 
589
590
  // Flush queued messages to the ORIGINAL tab, even if user switched tabs
590
591
  while (tab._queue && tab._queue.length > 0) {
@@ -592,8 +593,10 @@ async function ccSend() {
592
593
  await new Promise(function(r) { setTimeout(r, 1500); });
593
594
  }
594
595
  var next = tab._queue.shift();
596
+ var nextMessage = typeof next === 'string' ? next : next.message;
597
+ var nextIntentMetadata = typeof next === 'string' ? null : (next.intentMetadata || null);
595
598
  _renderQueueIndicator();
596
- wasAborted = await _ccDoSend(next, false, originTabId);
599
+ wasAborted = await _ccDoSend(nextMessage, false, originTabId, nextIntentMetadata);
597
600
  }
598
601
  }
599
602
 
@@ -608,13 +611,13 @@ function _renderQueueIndicator() {
608
611
  var el = document.createElement('div');
609
612
  el.className = 'cc-queue-item';
610
613
  el.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:12px;line-height:1.6;max-width:95%;align-self:flex-end;background:var(--blue);color:#fff;opacity:0.5;order:9999';
611
- el.innerHTML = escHtml(m) + '<div style="font-size:9px;opacity:0.7;font-style:italic;margin-top:2px">queued</div>';
614
+ el.innerHTML = escHtml(typeof m === 'string' ? m : m.message) + '<div style="font-size:9px;opacity:0.7;font-style:italic;margin-top:2px">queued</div>';
612
615
  msgs.appendChild(el);
613
616
  });
614
617
  if (msgs.scrollHeight - msgs.scrollTop - msgs.clientHeight < 150) msgs.scrollTop = msgs.scrollHeight;
615
618
  }
616
619
 
617
- async function _ccDoSend(message, skipUserMsg, forceTabId) {
620
+ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
618
621
  // Client-side /pin and /unpin — no LLM round-trip needed
619
622
  var pinMatch = message.match(/^\/(pin|unpin)\s+(.+)/i);
620
623
  if (pinMatch) {
@@ -762,7 +765,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId) {
762
765
  if (!isReconnect && res.status === 429 && (!activeTab._429retries || activeTab._429retries < 3)) {
763
766
  activeTab._429retries = (activeTab._429retries || 0) + 1;
764
767
  await new Promise(function(r) { setTimeout(r, 1500); });
765
- return await _ccConsumeStream({ message: message, tabId: activeTabId, sessionId: activeTab.sessionId || null, transcript: _ccBuildTranscript(activeTab) }, false);
768
+ return await _ccConsumeStream({ message: message, tabId: activeTabId, sessionId: activeTab.sessionId || null, transcript: _ccBuildTranscript(activeTab), intentMetadata: intentMetadata || null }, false);
766
769
  }
767
770
  activeTab._429retries = 0;
768
771
  var errText = await res.text();
@@ -871,7 +874,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId) {
871
874
  while (true) {
872
875
  var consume = await _ccConsumeStream(
873
876
  reconnectAttempts === 0
874
- ? { message: message, tabId: activeTabId, sessionId: activeTab.sessionId || null, transcript: _ccBuildTranscript(activeTab) }
877
+ ? { message: message, tabId: activeTabId, sessionId: activeTab.sessionId || null, transcript: _ccBuildTranscript(activeTab), intentMetadata: intentMetadata || null }
875
878
  : { tabId: activeTabId, sessionId: activeTab.sessionId || null, reconnect: true },
876
879
  reconnectAttempts > 0
877
880
  );
@@ -134,12 +134,13 @@ async function cmdSubmit() {
134
134
  const input = document.getElementById('cmd-input');
135
135
  const raw = input.value.trim();
136
136
  if (!raw) return showToast('cmd-toast', 'Type something first', false);
137
+ const parsed = cmdParseInput(raw);
137
138
 
138
139
  // Route to Command Center panel
139
140
  input.value = '';
140
141
  if (!_ccOpen) toggleCommandCenter();
141
142
  document.getElementById('cc-input').value = raw;
142
- ccSend();
143
+ ccSend({ intentMetadata: parsed });
143
144
  cmdSaveHistory(raw, 'cc');
144
145
  return;
145
146
  }
@@ -344,7 +344,7 @@ function _qaBuildAssistantHtml(text, opts) {
344
344
  '</div>';
345
345
  }
346
346
 
347
- const QA_WORK_ITEM_ACTION_TYPES = new Set(['dispatch', 'fix', 'implement', 'explore', 'review', 'test']);
347
+ const QA_WORK_ITEM_ACTION_TYPES = new Set(['dispatch', 'fix', 'explore', 'review', 'test']);
348
348
 
349
349
  function _qaActionFeedbackHandled(action, actionResult) {
350
350
  const type = String(actionResult?.type || action?.type || '');
package/dashboard.js CHANGED
@@ -1815,6 +1815,7 @@ function _extractActionsJson(segment) {
1815
1815
  }
1816
1816
 
1817
1817
  const CC_DISPATCH_ACTION_ALIASES = new Set(['fix', 'explore', 'review', 'test']);
1818
+ const CC_ACTION_INTENT_WORK_TYPES = new Set(['fix', 'implement', 'explore', 'review', 'test']);
1818
1819
 
1819
1820
  function normalizeCCAction(action) {
1820
1821
  if (!action || typeof action !== 'object') return action;
@@ -1827,6 +1828,161 @@ function normalizeCCAction(action) {
1827
1828
  return { ...action, type: 'dispatch', workType: action.workType || type };
1828
1829
  }
1829
1830
 
1831
+ function _ccCleanIntentString(value, max = 500) {
1832
+ if (typeof value !== 'string') return '';
1833
+ return value.replace(/[\0\r\n]+/g, ' ').replace(/\s+/g, ' ').trim().slice(0, max);
1834
+ }
1835
+
1836
+ function _ccNormalizeIntentMetadata(meta) {
1837
+ if (!meta || typeof meta !== 'object' || Array.isArray(meta)) return {};
1838
+ const out = {};
1839
+ for (const key of ['intent', 'type', 'title', 'description', 'priority', 'project', 'branchStrategy', 'branch_strategy']) {
1840
+ const value = _ccCleanIntentString(meta[key], key === 'description' ? 2000 : 300);
1841
+ if (value) out[key] = value;
1842
+ }
1843
+ if (Array.isArray(meta.agents)) {
1844
+ out.agents = meta.agents.map(a => _ccCleanIntentString(a, 80)).filter(Boolean);
1845
+ }
1846
+ if (Array.isArray(meta.projects)) {
1847
+ out.projects = meta.projects.map(p => _ccCleanIntentString(p, 120)).filter(Boolean);
1848
+ }
1849
+ if (meta.fanout === true) out.fanout = true;
1850
+ return out;
1851
+ }
1852
+
1853
+ function _messageExplicitlyRequestsMinionsOrchestration(message) {
1854
+ const text = String(message || '').toLowerCase();
1855
+ if (!text.trim()) return false;
1856
+ return [
1857
+ /\b(?:dispatch|delegate|assign|queue)\b/,
1858
+ /\b(?:create|open|file)\s+(?:a\s+)?(?:work\s*item|task)\b/,
1859
+ /\b(?:have|ask|tell)\s+(?:minions|an?\s+agent|[a-z][\w-]*)\s+(?:to\s+)?(?:fix|implement|review|test|explore|investigate)\b/,
1860
+ /\bminions\b[^.?!\n]*\b(?:fix|implement|review|test|explore|investigate|plan)\b/,
1861
+ /\b(?:create|make|draft|write)\s+(?:a\s+)?minions?\s+plan\b/,
1862
+ ].some(pattern => pattern.test(text));
1863
+ }
1864
+
1865
+ function _ccInferMessageActionIntent(message, source = 'command-center') {
1866
+ const text = String(message || '').trim();
1867
+ const lower = text.toLowerCase();
1868
+ if (!lower) return null;
1869
+ if (source === 'doc-chat' && !_messageExplicitlyRequestsMinionsOrchestration(text)) return null;
1870
+ if (/^\/plan\b/.test(lower) || /\b(?:make|create|draft|write|design|come up with)\s+(?:a\s+)?plan\b/.test(lower) || /\bplan\s+(?:this|that|it|for|how|out)\b/.test(lower)) {
1871
+ return { kind: 'plan' };
1872
+ }
1873
+ const workPatterns = [
1874
+ ['fix', /\b(?:fix|repair|resolve|patch|debug)\b|\b(?:bug|broken|crash|error|regression|failing|failure)\b/],
1875
+ ['implement', /\b(?:implement|build|add|create|ship)\b/],
1876
+ ['review', /\b(?:review|code review|inspect|audit)\b/],
1877
+ ['test', /\b(?:test|verify|validate|run tests?|write tests?|add tests?|coverage|build)\b/],
1878
+ ['explore', /\b(?:explore|investigate|research|analyze|understand|look into|map out|survey)\b/],
1879
+ ];
1880
+ for (const [workType, pattern] of workPatterns) {
1881
+ if (pattern.test(lower)) return { kind: 'work-item', workType };
1882
+ }
1883
+ return null;
1884
+ }
1885
+
1886
+ function _ccInferMetadataActionIntent(meta) {
1887
+ if (meta.intent === 'plan') return { kind: 'plan' };
1888
+ if (meta.intent === 'work-item' && CC_ACTION_INTENT_WORK_TYPES.has(String(meta.type || '').toLowerCase())) {
1889
+ return { kind: 'work-item', workType: String(meta.type).toLowerCase() };
1890
+ }
1891
+ return null;
1892
+ }
1893
+
1894
+ function _ccActionIntentTargetText(message, intent) {
1895
+ let text = _ccCleanIntentString(message, 500);
1896
+ text = text
1897
+ .replace(/^\/(?:plan|fix|implement|review|test|explore)\s+/i, '')
1898
+ .replace(/^(?:please\s+)?(?:dispatch|delegate|assign|queue)\s+(?:a\s+|an\s+)?(?:work\s*item|task|agent)?\s*(?:to\s+)?/i, '')
1899
+ .replace(/^(?:please\s+)?(?:create|open|file)\s+(?:a\s+)?(?:work\s*item|task)\s+(?:to\s+|for\s+)?/i, '')
1900
+ .replace(/^(?:please\s+)?(?:have|ask|tell)\s+(?:minions|an?\s+agent|[a-z][\w-]*)\s+(?:to\s+)?/i, '')
1901
+ .replace(/^(?:please\s+)?/, '')
1902
+ .trim();
1903
+ if (intent?.kind === 'plan') {
1904
+ text = text.replace(/^(?:make|create|draft|write|design|come up with)\s+(?:a\s+)?plan\s+(?:for\s+|to\s+|about\s+)?/i, '')
1905
+ .replace(/^plan\s+(?:out\s+)?(?:for\s+|how\s+to\s+|this\s+|that\s+|it\s+)?/i, '');
1906
+ } else if (intent?.workType) {
1907
+ const workType = intent.workType;
1908
+ const verbPattern = {
1909
+ fix: /^(?:fix|repair|resolve|patch|debug)\s+(?:the\s+|a\s+|an\s+)?/i,
1910
+ implement: /^(?:implement|build|add|create|ship)\s+(?:the\s+|a\s+|an\s+)?/i,
1911
+ review: /^(?:review|code review|inspect|audit)\s+(?:the\s+|a\s+|an\s+)?/i,
1912
+ test: /^(?:test|verify|validate|run tests?\s+(?:for\s+|on\s+)?|write tests?\s+(?:for\s+)?|add tests?\s+(?:for\s+)?)\s*(?:the\s+|a\s+|an\s+)?/i,
1913
+ explore: /^(?:explore|investigate|research|analyze|understand|look into|map out|survey)\s+(?:the\s+|a\s+|an\s+)?/i,
1914
+ }[workType];
1915
+ if (verbPattern) text = text.replace(verbPattern, '');
1916
+ text = text.replace(/^(?:a\s+)?(?:fix|review|test|implementation|exploration|investigation)\s+(?:for\s+|to\s+|of\s+)?/i, '');
1917
+ }
1918
+ return text.replace(/^(?:for|to|of|on|about)\s+/i, '').trim();
1919
+ }
1920
+
1921
+ function _ccIntentHasConcreteTarget(message, metadataTitle, intent) {
1922
+ const raw = String(message || '');
1923
+ if (/\b(?:PR|pull request|issue)\s*#?\d+\b/i.test(raw) || /\bW-[a-z0-9][a-z0-9-]*\b/i.test(raw) || /https?:\/\//i.test(raw)) return true;
1924
+ const target = _ccActionIntentTargetText(metadataTitle || raw, intent)
1925
+ .replace(/[.!?]+$/g, '')
1926
+ .trim()
1927
+ .toLowerCase();
1928
+ if (!target) return false;
1929
+ if (/^(?:this|that|it|these|those|same|above|the above|here|there)(?:\s+(?:one|thing|issue|bug|task|request|change|pr|pull request|code|test|plan|doc|document|file))?$/.test(target)) {
1930
+ return false;
1931
+ }
1932
+ return target.length >= 3;
1933
+ }
1934
+
1935
+ function _ccIntentTitle(message, metadataTitle, intent) {
1936
+ const metaTitle = _ccCleanIntentString(metadataTitle, 300);
1937
+ if (metaTitle && _ccIntentHasConcreteTarget(message, metaTitle, intent)) return metaTitle;
1938
+ const cleaned = _ccCleanIntentString(message, 300).replace(/^\/plan\s+/i, 'plan ');
1939
+ if (!cleaned) return '';
1940
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
1941
+ }
1942
+
1943
+ function _ccFallbackMissingTargetError(intent) {
1944
+ const label = intent?.kind === 'plan' ? 'plan' : (intent?.workType || 'dispatch');
1945
+ return `Missing target for ${label} request. Specify a concrete title, PR/work item, file, or feature to ${label}.`;
1946
+ }
1947
+
1948
+ function _actionsWithIntentFallback(actions, { message = '', intentMetadata = null, source = 'command-center' } = {}) {
1949
+ const existing = Array.isArray(actions) ? actions : [];
1950
+ if (existing.length > 0) return existing;
1951
+ const meta = _ccNormalizeIntentMetadata(intentMetadata);
1952
+ const messageIntent = _ccInferMessageActionIntent(message, source);
1953
+ const metadataIntent = source === 'doc-chat' ? null : _ccInferMetadataActionIntent(meta);
1954
+ const intent = messageIntent || metadataIntent;
1955
+ if (!intent) return existing;
1956
+
1957
+ const title = _ccIntentTitle(message, meta.title, intent);
1958
+ const hasTarget = _ccIntentHasConcreteTarget(message, meta.title || title, intent);
1959
+ const description = meta.description || _ccCleanIntentString(message, 2000);
1960
+ const common = {
1961
+ ...(title ? { title } : {}),
1962
+ ...(description ? { description } : {}),
1963
+ ...(meta.priority ? { priority: meta.priority } : {}),
1964
+ ...(meta.project ? { project: meta.project } : {}),
1965
+ ...(Array.isArray(meta.agents) && meta.agents.length ? { agents: meta.agents } : {}),
1966
+ ...(meta.fanout ? { scope: 'fan-out' } : {}),
1967
+ };
1968
+ if (intent.kind === 'plan') {
1969
+ const action = {
1970
+ type: 'plan',
1971
+ ...common,
1972
+ branchStrategy: meta.branchStrategy || meta.branch_strategy || 'parallel',
1973
+ };
1974
+ if (!hasTarget) action._intentFallbackError = _ccFallbackMissingTargetError(intent);
1975
+ return [action];
1976
+ }
1977
+ const action = {
1978
+ type: 'dispatch',
1979
+ workType: intent.workType,
1980
+ ...common,
1981
+ };
1982
+ if (!hasTarget) action._intentFallbackError = _ccFallbackMissingTargetError(intent);
1983
+ return [action];
1984
+ }
1985
+
1830
1986
  function parseCCActions(text) {
1831
1987
  let actions = [];
1832
1988
  let displayText = stripCCActionsForDisplay(text);
@@ -2262,6 +2418,8 @@ function _ccValidateAction(action) {
2262
2418
  case 'dispatch': case 'fix': case 'explore': case 'review': case 'test':
2263
2419
  if (!action.title || typeof action.title !== 'string' || !action.title.trim()) return `${action.type} action missing required field: title`;
2264
2420
  return null;
2421
+ case 'implement':
2422
+ return 'Unsupported action type "implement"; use type="dispatch" with workType="implement".';
2265
2423
  case 'build-and-test':
2266
2424
  if (!action.pr) return 'build-and-test action missing required field: pr';
2267
2425
  return null;
@@ -2586,6 +2744,15 @@ async function executeCCActions(actions, { source = 'command-center', inferredPr
2586
2744
  const results = [];
2587
2745
  for (const rawAction of actions) {
2588
2746
  const action = normalizeCCAction(rawAction);
2747
+ if (action?._intentFallbackError) {
2748
+ results.push({
2749
+ type: action.type || 'dispatch',
2750
+ ...(action.workType ? { workType: action.workType } : {}),
2751
+ error: action._intentFallbackError,
2752
+ missingTarget: true,
2753
+ });
2754
+ continue;
2755
+ }
2589
2756
  const validationError = _ccValidateAction(action);
2590
2757
  if (validationError) {
2591
2758
  results.push({ type: action?.type || 'unknown', error: validationError });
@@ -2887,7 +3054,7 @@ async function executeDocChatActions(actions, { filePath = null } = {}) {
2887
3054
  return executeCCActions(actions, { source: 'doc-chat', inferredProject: _inferDocChatProject(filePath) });
2888
3055
  }
2889
3056
 
2890
- const DOC_CHAT_WORK_ITEM_ACTION_TYPES = new Set(['dispatch', 'fix', 'implement', 'explore', 'review', 'test']);
3057
+ const DOC_CHAT_WORK_ITEM_ACTION_TYPES = new Set(['dispatch', 'fix', 'explore', 'review', 'test']);
2891
3058
 
2892
3059
  function _buildDocChatActionFeedback(actions, actionResults) {
2893
3060
  if (!Array.isArray(actions) || !Array.isArray(actionResults)) return [];
@@ -5913,7 +6080,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
5913
6080
  }
5914
6081
  }
5915
6082
 
5916
- const { answer, content, actions, actionParseError, partial, warning, toolUses, error: ccError } = await ccDocCall({
6083
+ let { answer, content, actions, actionParseError, partial, warning, toolUses, error: ccError } = await ccDocCall({
5917
6084
  message: body.message, document: currentContent, title: body.title,
5918
6085
  filePath: body.filePath, selection: body.selection, canEdit, isJson,
5919
6086
  model: body.model || undefined,
@@ -5921,6 +6088,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
5921
6088
  transcript: body.transcript,
5922
6089
  onAbortReady: (abort) => { _docAbort = abort; },
5923
6090
  });
6091
+ actions = _actionsWithIntentFallback(actions, { message: body.message, source: 'doc-chat' });
5924
6092
  const actionResults = await executeDocChatActions(actions, { filePath: body.filePath });
5925
6093
  const actionFeedback = _buildDocChatActionFeedback(actions, actionResults);
5926
6094
  const finalize = _finalizeDocChatEdit({
@@ -6005,7 +6173,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
6005
6173
 
6006
6174
  try {
6007
6175
 
6008
- const { answer, content, actions, actionParseError, partial, warning, toolUses, error: ccError } = await ccDocCallStreaming({
6176
+ let { answer, content, actions, actionParseError, partial, warning, toolUses, error: ccError } = await ccDocCallStreaming({
6009
6177
  message: body.message, document: currentContent, title: body.title,
6010
6178
  filePath: body.filePath, selection: body.selection, canEdit, isJson,
6011
6179
  model: body.model || undefined,
@@ -6016,6 +6184,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
6016
6184
  onToolUse: (name, input) => { writeDocEvent({ type: 'tool', name, input: _lightToolInput(input) }); },
6017
6185
  onRetry: (attempt) => { writeDocEvent({ type: 'progress', attempt }); },
6018
6186
  });
6187
+ actions = _actionsWithIntentFallback(actions, { message: body.message, source: 'doc-chat' });
6019
6188
  const actionResults = await executeDocChatActions(actions, { filePath: body.filePath });
6020
6189
  const actionFeedback = _buildDocChatActionFeedback(actions, actionResults);
6021
6190
  const finalize = _finalizeDocChatEdit({
@@ -6545,6 +6714,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
6545
6714
  }
6546
6715
 
6547
6716
  const parsed = parseCCActions(result.text);
6717
+ parsed.actions = _actionsWithIntentFallback(parsed.actions, {
6718
+ message: body.message,
6719
+ intentMetadata: body.intentMetadata,
6720
+ source: 'command-center',
6721
+ });
6548
6722
  const toolUses = Array.isArray(result.toolUses) ? result.toolUses : _extractToolUsesFromRaw(result.raw);
6549
6723
  // Safety net: detect /loop invocation and convert to create-watch
6550
6724
  const _loopWatch = _detectLoopInvocation(parsed.text, parsed.actions, toolUses, body.message);
@@ -6874,6 +7048,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
6874
7048
 
6875
7049
  // Send final result with actions — execute server-side first
6876
7050
  let { text: displayText, actions, _actionParseError } = parseCCActions(result.text);
7051
+ actions = _actionsWithIntentFallback(actions, {
7052
+ message: body.message,
7053
+ intentMetadata: body.intentMetadata,
7054
+ source: 'command-center',
7055
+ });
6877
7056
  // Safety net: detect /loop invocation and convert to create-watch
6878
7057
  const _loopWatch = _detectLoopInvocation(displayText, actions, toolUses, body.message);
6879
7058
  if (_loopWatch) {
@@ -8511,6 +8690,7 @@ module.exports = {
8511
8690
  _resolveSkillReadPath,
8512
8691
  DOC_CHAT_DOCUMENT_DELIMITER,
8513
8692
  _ccValidateAction,
8693
+ _actionsWithIntentFallback,
8514
8694
  _messageExplicitlyRequestsMonitoring,
8515
8695
  _filterImplicitPostDispatchActions,
8516
8696
  _findDuplicateWorkItemCreate: findDuplicateWorkItemCreate,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-08T20:57:25.233Z"
4
+ "cachedAt": "2026-05-08T20:58:39.806Z"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1808",
3
+ "version": "0.1.1809",
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"