@yemi33/minions 0.1.2245 → 0.1.2247

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.
@@ -3906,12 +3906,47 @@ function _deferRetryWithCounter(meta, detection, counterField, maxCount, pending
3906
3906
  if (!wiPath) return reason;
3907
3907
 
3908
3908
  let finalStatus = WI_STATUS.PENDING;
3909
+ let systematicPhantom = null;
3909
3910
  try {
3910
3911
  mutateJsonFileLocked(wiPath, data => {
3911
3912
  if (!Array.isArray(data)) return data;
3912
3913
  const w = data.find(i => i.id === itemId);
3913
3914
  if (!w) return data;
3914
3915
  const retries = w[counterField] || 0;
3916
+
3917
+ // Systematic phantom detection: after 2+ phantom completions spanning
3918
+ // 2+ different agents, the failure is likely content-filter or prompt-
3919
+ // malformed. Mark non-retryable immediately so human can intervene.
3920
+ if (counterField === '_phantomRetryCount') {
3921
+ const phantomAgent = meta?._agentId || w.dispatched_to;
3922
+ if (!w._phantomAgents || typeof w._phantomAgents !== 'object' || Array.isArray(w._phantomAgents)) {
3923
+ w._phantomAgents = {};
3924
+ }
3925
+ if (phantomAgent) {
3926
+ w._phantomAgents[phantomAgent] = (w._phantomAgents[phantomAgent] || 0) + 1;
3927
+ }
3928
+ const distinctAgents = Object.keys(w._phantomAgents);
3929
+ if (distinctAgents.length >= 2 && retries >= 1) {
3930
+ w.status = WI_STATUS.FAILED;
3931
+ w.failReason = `Systematic phantom completion across ${distinctAgents.length} agents ` +
3932
+ `(${distinctAgents.join(', ')}) — likely a content filter triggered by the task description ` +
3933
+ `or a malformed prompt. Manual intervention required.`;
3934
+ w._failureClass = 'phantom-all-agents';
3935
+ w.failedAt = ts();
3936
+ delete w.completedAt;
3937
+ delete w.dispatched_at;
3938
+ delete w.dispatched_to;
3939
+ delete w._pendingReason;
3940
+ delete w._phantomCompletion;
3941
+ delete w._phantomBranch;
3942
+ finalStatus = WI_STATUS.FAILED;
3943
+ systematicPhantom = { distinctCount: distinctAgents.length, agents: distinctAgents };
3944
+ log('warn', `Work item ${itemId} systematically phantoms across ${distinctAgents.length} agents ` +
3945
+ `(${distinctAgents.join(', ')}) — marking non-retryable (phantom-all-agents)`);
3946
+ return data;
3947
+ }
3948
+ }
3949
+
3915
3950
  if (retries < maxCount) {
3916
3951
  w.status = WI_STATUS.PENDING;
3917
3952
  w[counterField] = retries + 1;
@@ -3963,6 +3998,20 @@ function _deferRetryWithCounter(meta, detection, counterField, maxCount, pending
3963
3998
  } catch (err) {
3964
3999
  log('warn', `${pendingReason} gate: ${err.message}`);
3965
4000
  }
4001
+ // Post diagnostic inbox note when systematic phantom detection fired.
4002
+ if (systematicPhantom) {
4003
+ shared.writeToInbox('engine', `phantom-all-agents-${itemId}`,
4004
+ `# Systematic phantom completion for ${itemId}\n\n` +
4005
+ `**Work item:** \`${itemId}\` — ${meta.item?.title || ''}\n` +
4006
+ `**Agents that all phantom-completed:** ${systematicPhantom.agents.join(', ')}\n\n` +
4007
+ `All ${systematicPhantom.distinctCount} agents produced phantom completions ` +
4008
+ `(process exited 0 but emitted no result event). This pattern is typically caused by:\n` +
4009
+ `- A runtime content filter triggered by credential-shaped strings in the task description\n` +
4010
+ `- A malformed prompt that causes the runtime to bail out silently\n\n` +
4011
+ `The work item has been marked non-retryable. **Manual intervention required.**\n`,
4012
+ null,
4013
+ { sourceItem: itemId, reason: 'phantom-all-agents' });
4014
+ }
3966
4015
  return reason;
3967
4016
  }
3968
4017
 
@@ -5019,6 +5068,9 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
5019
5068
  log('info', `Phantom-completion recovered for ${meta.item.id} via ls-remote + PR auto-link — no retry needed`);
5020
5069
  } else {
5021
5070
  skipDoneStatus = true;
5071
+ // Stamp agentId on meta so _deferRetryWithCounter can track
5072
+ // phantom completions per agent (systematic phantom detection).
5073
+ if (!meta._agentId) meta._agentId = agentId;
5022
5074
  const reason = isPhantomDetection
5023
5075
  ? deferPhantomCompletion(meta, nonTerminalCompletion)
5024
5076
  : deferNonTerminalCompletion(meta, nonTerminalCompletion);
package/engine/shared.js CHANGED
@@ -415,6 +415,21 @@ function redactSecrets(value, options = {}) {
415
415
  return value;
416
416
  }
417
417
 
418
+ // Authorization header pattern broader than _BEARER_RE: catches already-redacted
419
+ // placeholder forms (e.g. `Authorization: Bearer <REDACTED>`) that still look
420
+ // credential-shaped to Copilot CLI safety filters and cause silent phantom exits.
421
+ const _AUTH_HEADER_RE = /\bAuthorization\s*:\s*Bearer\s+\S+/gi;
422
+
423
+ // Redactor applied to WI description text before it is injected into an agent
424
+ // prompt. Applies the standard log redactor (_redactString) first, then catches
425
+ // any remaining Authorization: Bearer header — including already-redacted forms
426
+ // with placeholder values — that would trigger Copilot CLI safety bail-outs.
427
+ function redactPromptDescription(s) {
428
+ if (s == null) return s;
429
+ if (typeof s !== 'string' || s.length === 0) return s;
430
+ return _redactString(s).replace(_AUTH_HEADER_RE, 'Authorization: Bearer [REDACTED-IN-DESC]');
431
+ }
432
+
418
433
  // ── Log Buffering ──────────────────────────────────────────────────────────
419
434
  // Buffer log entries in memory and flush to disk periodically to reduce lock
420
435
  // contention (~139 calls/tick → 1 lock acquisition per flush).
@@ -9089,6 +9104,7 @@ module.exports = {
9089
9104
  openAppendLogFd,
9090
9105
  flushLogs,
9091
9106
  redactSecrets,
9107
+ redactPromptDescription,
9092
9108
  slugify,
9093
9109
  getPrAutomationCauses,
9094
9110
  hasPrAutomationCause,
package/engine.js CHANGED
@@ -7337,9 +7337,9 @@ function renderProjectWorkItemPromptForAgent(item, workType, agentId, config, pr
7337
7337
  item_id: item.id,
7338
7338
  item_name: item.title || item.id,
7339
7339
  item_priority: item.priority || 'medium',
7340
- item_description: item.description || '',
7340
+ item_description: shared.redactPromptDescription(item.description || ''),
7341
7341
  item_complexity: item.complexity || item.estimated_complexity || 'medium',
7342
- task_description: item.title + (item.description ? '\n\n' + item.description : ''),
7342
+ task_description: shared.redactPromptDescription(item.title + (item.description ? '\n\n' + item.description : '')),
7343
7343
  task_id: item.id,
7344
7344
  work_type: workType,
7345
7345
  source_plan: item.sourcePlan || '',
@@ -8575,9 +8575,9 @@ function discoverCentralWorkItems(config) {
8575
8575
  item_id: item.id,
8576
8576
  item_name: item.title || item.id,
8577
8577
  item_priority: item.priority || 'medium',
8578
- item_description: item.description || '',
8578
+ item_description: shared.redactPromptDescription(item.description || ''),
8579
8579
  item_complexity: item.complexity || item.estimated_complexity || 'medium',
8580
- task_description: item.title + (item.description ? '\n\n' + item.description : ''),
8580
+ task_description: shared.redactPromptDescription(item.title + (item.description ? '\n\n' + item.description : '')),
8581
8581
  task_id: item.id,
8582
8582
  work_type: workType,
8583
8583
  additional_context: item.prompt ? `## Additional Context\n\n${item.prompt}` : '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2245",
3
+ "version": "0.1.2247",
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"