@yemi33/minions 0.1.1744 → 0.1.1745

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,13 +1,15 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1744 (2026-05-06)
3
+ ## 0.1.1745 (2026-05-06)
4
+
5
+ ### Features
6
+ - fix doc-chat failure bugs from Ripley investigation (#2103)
7
+
8
+ ## 0.1.1743 (2026-05-06)
4
9
 
5
10
  ### Fixes
6
11
  - isolate meeting tests off live MEETINGS_DIR (#2111)
7
12
 
8
- ### Other
9
- - test(github): add unit tests for slug-backoff and verdict helpers (#2092)
10
-
11
13
  ## 0.1.1742 (2026-05-06)
12
14
 
13
15
  ### Fixes
@@ -499,7 +499,7 @@ async function _processQaMessage(message, selection, opts) {
499
499
  selection: selection,
500
500
  filePath: capturedFilePath || null,
501
501
  model: window._lastStatus?.autoMode?.ccModel || undefined,
502
- contentHash: capturedDocContext.content ? capturedDocContext.content.length + ':' + capturedDocContext.content.charCodeAt(0) + ':' + capturedDocContext.content.charCodeAt(capturedDocContext.content.length - 1) : undefined,
502
+ contentHash: capturedDocContext.content ? (function(s) { const m = Math.floor(s.length / 2); return s.length + ':' + s.charCodeAt(0) + ':' + s.charCodeAt(m) + ':' + s.charCodeAt(s.length - 1); })(capturedDocContext.content) : undefined,
503
503
  }),
504
504
  });
505
505
  let sessionDocContext = { ...capturedDocContext };
@@ -521,6 +521,12 @@ async function _processQaMessage(message, selection, opts) {
521
521
  async function _qaHandleStreamEvent(evt) {
522
522
  if (!evt || !evt.type) return;
523
523
  if (evt.type === 'heartbeat') return;
524
+ if (evt.type === 'progress') {
525
+ // Backend is retrying (attempt 2 or 3) — reset stall watchdog so the next
526
+ // attempt gets its own full stall window instead of sharing the first attempt's.
527
+ _resetQaStreamWatchdog();
528
+ return;
529
+ }
524
530
  if (evt.type === 'chunk') {
525
531
  _resetQaStreamWatchdog();
526
532
  streamedText = evt.text || '';
package/dashboard.js CHANGED
@@ -2377,7 +2377,7 @@ async function ccCall(message, { store = 'cc', sessionKey, extraContext, label =
2377
2377
  return result;
2378
2378
  }
2379
2379
 
2380
- async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext, label = 'command-center', timeout = CC_CALL_TIMEOUT_MS, maxTurns, allowedTools = 'Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch', skipStatePreamble = false, model, onAbortReady, onChunk, onToolUse, systemPrompt = CC_STATIC_SYSTEM_PROMPT } = {}) {
2380
+ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext, label = 'command-center', timeout = CC_CALL_TIMEOUT_MS, maxTurns, allowedTools = 'Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch', skipStatePreamble = false, model, onAbortReady, onChunk, onToolUse, onRetry, systemPrompt = CC_STATIC_SYSTEM_PROMPT } = {}) {
2381
2381
  if (!maxTurns) maxTurns = CONFIG.engine?.ccMaxTurns || shared.ENGINE_DEFAULTS.ccMaxTurns;
2382
2382
  if (!model) model = CONFIG.engine?.ccModel || shared.ENGINE_DEFAULTS.ccModel;
2383
2383
  const ccEffort = CONFIG.engine?.ccEffort || shared.ENGINE_DEFAULTS.ccEffort;
@@ -2430,6 +2430,7 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
2430
2430
  }
2431
2431
  }
2432
2432
 
2433
+ if (onRetry) onRetry(2);
2433
2434
  const freshPrompt = buildPrompt();
2434
2435
  const p2 = llm.callLLMStreaming(freshPrompt, systemPrompt, {
2435
2436
  timeout, label, model, maxTurns, allowedTools, effort: ccEffort, direct: true,
@@ -2450,6 +2451,7 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
2450
2451
  if (maxTurns <= 1) return result;
2451
2452
  console.log(`[${label}] Fresh call also failed (code=${result.code}, empty=${!result.text}), retrying once more...`);
2452
2453
  await new Promise(r => setTimeout(r, 2000));
2454
+ if (onRetry) onRetry(3);
2453
2455
  const p3 = llm.callLLMStreaming(freshPrompt, systemPrompt, {
2454
2456
  timeout, label, model, maxTurns, allowedTools, effort: ccEffort, direct: true,
2455
2457
  engineConfig: CONFIG.engine,
@@ -2467,10 +2469,13 @@ async function ccCallStreaming(message, { store = 'cc', sessionKey, extraContext
2467
2469
  return result;
2468
2470
  }
2469
2471
 
2470
- // Lightweight content fingerprint — same algorithm used browser-side (no crypto needed)
2472
+ // Lightweight content fingerprint — same algorithm used browser-side (no crypto needed).
2473
+ // Uses length + first + middle + last char codes. Collisions on same-length strings with
2474
+ // identical first/middle/last chars are rare enough for a staleness check (not a security hash).
2471
2475
  function contentFingerprint(str) {
2472
2476
  if (!str) return '';
2473
- return str.length + ':' + str.charCodeAt(0) + ':' + str.charCodeAt(str.length - 1);
2477
+ const mid = Math.floor(str.length / 2);
2478
+ return str.length + ':' + str.charCodeAt(0) + ':' + str.charCodeAt(mid) + ':' + str.charCodeAt(str.length - 1);
2474
2479
  }
2475
2480
 
2476
2481
  function _parseDocChatResultText(text, { allowActions = false } = {}) {
@@ -2524,6 +2529,17 @@ function _formatDocChatContext({ document, title, filePath, selection, canEdit,
2524
2529
  return context;
2525
2530
  }
2526
2531
 
2532
+ // Map errorClass codes from the runtime adapter to actionable user-facing messages.
2533
+ // sessionPreserved=true means ccCall preserved the session — user can retry immediately.
2534
+ function _docChatErrorMessage(errorClass, sessionPreserved = false) {
2535
+ if (errorClass === 'auth-failure') return 'Claude authentication failed — run `claude auth` or check your API key, then try again.';
2536
+ if (errorClass === 'context-limit') return 'Session context is too long. Click "Clear" to start a fresh conversation.';
2537
+ if (errorClass === 'budget-exceeded') return 'API budget exceeded — check your Claude account spending limit.';
2538
+ if (errorClass === 'crash') return 'Claude runtime crashed unexpectedly. Try again.';
2539
+ if (sessionPreserved) return 'Temporary connection issue — your conversation is intact, send your message again.';
2540
+ return 'Failed to process request. Try again.';
2541
+ }
2542
+
2527
2543
  // Build the doc-chat extraContext for a single ccCall pass — refreshed on retry
2528
2544
  // so a fresh-session retry includes the full document instead of relying on the
2529
2545
  // dead session's prior turn for context.
@@ -2555,14 +2571,14 @@ async function _retryDocChatAfterResumeFailure({ result, initialPass, freshSessi
2555
2571
  }
2556
2572
 
2557
2573
  // Build the {error} envelope returned to the dashboard when doc-chat ultimately
2558
- // fails. Keeps the polite user-facing message but exposes the runtime's real
2559
- // stderr / exit code / errorClass so the UI can render the cause and so future
2560
- // failures are debuggable from logs.
2561
- function _docChatFailureResponse(label, filePath, result) {
2574
+ // fails. Surfaces an actionable user-facing message (via _docChatErrorMessage)
2575
+ // plus the runtime's real stderr / exit code / errorClass so the UI can render
2576
+ // the cause and so future failures are debuggable from logs.
2577
+ function _docChatFailureResponse(label, filePath, result, sessionPreserved = false) {
2562
2578
  const stderrTail = (result.stderr || '').slice(-2048);
2563
- console.error(`[${label}] Failed: code=${result.code}, empty=${!result.text}, filePath=${filePath}, errorClass=${result.errorClass || 'null'}, stderr=${stderrTail.slice(0, 200)}`);
2579
+ console.error(`[${label}] Failed: code=${result.code}, errorClass=${result.errorClass || 'null'}, sessionPreserved=${sessionPreserved}, empty=${!result.text}, filePath=${filePath}, stderr=${stderrTail.slice(0, 200)}`);
2564
2580
  return {
2565
- answer: 'Failed to process request. Try again.',
2581
+ answer: _docChatErrorMessage(result.errorClass, sessionPreserved),
2566
2582
  content: null,
2567
2583
  actions: [],
2568
2584
  error: {
@@ -2574,6 +2590,7 @@ function _docChatFailureResponse(label, filePath, result) {
2574
2590
  };
2575
2591
  }
2576
2592
 
2593
+
2577
2594
  // Doc-specific wrapper — adds document context, parses ---DOCUMENT---
2578
2595
  async function ccDocCall({ message, document, title, filePath, selection, canEdit, isJson, model, freshSession, onAbortReady }) {
2579
2596
  const sessionKey = filePath || title;
@@ -2628,13 +2645,14 @@ async function ccDocCall({ message, document, title, filePath, selection, canEdi
2628
2645
  }
2629
2646
 
2630
2647
  if (result.code !== 0 || !result.text) {
2631
- return _docChatFailureResponse('doc-chat', filePath, result);
2648
+ const sessionPreserved = !!(resolveSession('doc', sessionKey)?.sessionId);
2649
+ return _docChatFailureResponse('doc-chat', filePath, result, sessionPreserved);
2632
2650
  }
2633
2651
 
2634
2652
  return _parseDocChatResultText(result.text, { allowActions });
2635
2653
  }
2636
2654
 
2637
- async function ccDocCallStreaming({ message, document, title, filePath, selection, canEdit, isJson, model, freshSession, onAbortReady, onChunk, onToolUse }) {
2655
+ async function ccDocCallStreaming({ message, document, title, filePath, selection, canEdit, isJson, model, freshSession, onAbortReady, onChunk, onToolUse, onRetry }) {
2638
2656
  const sessionKey = filePath || title;
2639
2657
  const docSlice = document.slice(0, 20000);
2640
2658
 
@@ -2660,6 +2678,7 @@ async function ccDocCallStreaming({ message, document, title, filePath, selectio
2660
2678
  onAbortReady,
2661
2679
  onChunk: (text) => { if (onChunk) onChunk(_docChatDisplayText(text, { allowActions })); },
2662
2680
  onToolUse,
2681
+ onRetry,
2663
2682
  });
2664
2683
  };
2665
2684
 
@@ -2682,7 +2701,8 @@ async function ccDocCallStreaming({ message, document, title, filePath, selectio
2682
2701
  }
2683
2702
 
2684
2703
  if (result.code !== 0 || !result.text) {
2685
- return _docChatFailureResponse('doc-chat-stream', filePath, result);
2704
+ const sessionPreserved = !!(resolveSession('doc', sessionKey)?.sessionId);
2705
+ return _docChatFailureResponse('doc-chat-stream', filePath, result, sessionPreserved);
2686
2706
  }
2687
2707
 
2688
2708
  return _parseDocChatResultText(result.text, { allowActions });
@@ -4903,6 +4923,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
4903
4923
  onAbortReady: (abort) => { _docAbort = abort; },
4904
4924
  onChunk: (text) => { writeDocEvent({ type: 'chunk', text }); },
4905
4925
  onToolUse: (name, input) => { writeDocEvent({ type: 'tool', name, input: _lightToolInput(input) }); },
4926
+ onRetry: (attempt) => { writeDocEvent({ type: 'progress', attempt }); },
4906
4927
  });
4907
4928
  const actionResults = await executeDocChatActions(actions);
4908
4929
  const donePayload = (extra = {}) => ({
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-06T01:39:28.821Z"
4
+ "cachedAt": "2026-05-06T02:33:28.238Z"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1744",
3
+ "version": "0.1.1745",
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"