agentxchain 2.42.0 → 2.43.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxchain",
3
- "version": "2.42.0",
3
+ "version": "2.43.0",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -660,29 +660,39 @@ export function normalizeTurnResult(tr, config, context = {}) {
660
660
  }
661
661
  }
662
662
 
663
- // ── Rule 3: review_only terminal needs_human → run_completion_request ──
663
+ // ── Rule 3: review_only needs_human → lifecycle correction ──────────
664
+ // review_only roles cannot perform work that genuinely requires human
665
+ // intervention. If the model says "needs_human" with an affirmative,
666
+ // non-blocker reason, correct to the appropriate lifecycle signal:
667
+ // terminal phase → run_completion_request, non-terminal → phase_transition.
664
668
  if (
665
669
  context.writeAuthority === 'review_only' &&
666
670
  context.phase &&
667
671
  routing &&
668
672
  normalized.status === 'needs_human' &&
669
- normalized.run_completion_request !== false
673
+ normalized.run_completion_request !== false &&
674
+ typeof normalized.needs_human_reason === 'string'
670
675
  ) {
671
- const phaseNames = Object.keys(routing);
672
- const isTerminal = phaseNames.indexOf(context.phase) === phaseNames.length - 1;
673
- if (isTerminal && typeof normalized.needs_human_reason === 'string') {
674
- const reason = normalized.needs_human_reason.toLowerCase();
675
- const affirmativeSignals = /\b(approv|ship|release|sign.?off|no.?block|ready|pass|good|accept|green.?light)\b/i;
676
- const blockerSignals = /\b(critical|security|fail|block|cannot|must.?fix|regression|vulnerab|reject|unsafe|broken)\b/i;
677
- const isAffirmative = affirmativeSignals.test(reason);
678
- const isBlocker = blockerSignals.test(reason);
679
- if (isAffirmative && !isBlocker) {
676
+ const reason = normalized.needs_human_reason.toLowerCase();
677
+ const affirmativeSignals = /\b(approv|ship|release|sign.?off|no.?block|ready|pass|good|accept|green.?light|proceed|move.?forward|complet|done|lgtm|satisf|recommend)\b/i;
678
+ const blockerSignals = /\b(critical|security|fail|block|cannot|must.?fix|regression|vulnerab|reject|unsafe|broken)\b/i;
679
+ const isAffirmative = affirmativeSignals.test(reason);
680
+ const isBlocker = blockerSignals.test(reason);
681
+ if (isAffirmative && !isBlocker) {
682
+ if (isTerminalPhase) {
680
683
  corrections.push(
681
684
  `status: corrected review_only terminal "needs_human" to run_completion_request — reason indicated ship readiness ("${normalized.needs_human_reason.slice(0, 80)}"), not a genuine blocker`
682
685
  );
683
686
  normalized.status = 'completed';
684
687
  normalized.run_completion_request = true;
685
688
  delete normalized.needs_human_reason;
689
+ } else if (nextPhase) {
690
+ corrections.push(
691
+ `status: corrected review_only "needs_human" to phase_transition_request "${nextPhase}" — reason indicated forward progress ("${normalized.needs_human_reason.slice(0, 80)}"), not a genuine blocker`
692
+ );
693
+ normalized.status = 'completed';
694
+ normalized.phase_transition_request = nextPhase;
695
+ delete normalized.needs_human_reason;
686
696
  }
687
697
  }
688
698
  }