agentxchain 2.155.3 → 2.155.5

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.155.3",
3
+ "version": "2.155.5",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  */
14
14
 
15
15
  import { existsSync, readFileSync } from 'fs';
16
- import { join } from 'path';
16
+ import { dirname, join } from 'path';
17
17
  import { getActiveTurn } from './governed-state.js';
18
18
  import { getInvalidPhaseTransitionReason } from './gate-evaluator.js';
19
19
  import { validateIdleExpansionTurnResult } from './idle-expansion-result-validator.js';
@@ -71,6 +71,8 @@ export function validateStagedTurnResult(root, state, config, opts = {}) {
71
71
  return result('schema', 'schema_error', [`Invalid JSON in ${stagingRel}: ${err.message}`]);
72
72
  }
73
73
 
74
+ const activeTurn = getActiveTurn(state) || state?.current_turn || null;
75
+
74
76
  // ── Pre-validation normalization ───────────────────────────────────────
75
77
  // Build context for role/phase-aware normalization rules
76
78
  const normContext = {};
@@ -80,7 +82,6 @@ export function validateStagedTurnResult(root, state, config, opts = {}) {
80
82
  // current_turn compatibility alias for callers that pass a state shape
81
83
  // built outside loadProjectState() (e.g. raw fixtures). Both surfaces are
82
84
  // live per DEC-CURRENT-TURN-COMPAT-ALIAS-001 — current_turn is not legacy.
83
- const activeTurn = getActiveTurn(state) || state.current_turn;
84
85
  if (activeTurn) {
85
86
  const roleKey = activeTurn.assigned_role || activeTurn.role;
86
87
  normContext.assignedRole = roleKey;
@@ -92,7 +93,17 @@ export function validateStagedTurnResult(root, state, config, opts = {}) {
92
93
  }
93
94
  const { normalized, corrections } = normalizeTurnResult(turnResult, config, normContext);
94
95
  turnResult = normalized;
95
- const normWarnings = corrections.map((c) => `[normalized] ${c}`);
96
+ const sidecarResult = maybeAttachIdleExpansionSidecar(
97
+ root,
98
+ stagingRel,
99
+ turnResult,
100
+ buildIdleExpansionValidationContext(state, opts, activeTurn),
101
+ );
102
+ turnResult = sidecarResult.turnResult;
103
+ const normWarnings = [
104
+ ...corrections.map((c) => `[normalized] ${c}`),
105
+ ...sidecarResult.warnings,
106
+ ];
96
107
 
97
108
  // ── Stage A: Schema Validation ─────────────────────────────────────────
98
109
  const schemaErrors = validateSchema(turnResult);
@@ -100,7 +111,6 @@ export function validateStagedTurnResult(root, state, config, opts = {}) {
100
111
  return result('schema', 'schema_error', schemaErrors);
101
112
  }
102
113
 
103
- const activeTurn = getActiveTurn(state) || state?.current_turn || null;
104
114
  const idleExpansionResult = validateIdleExpansionTurnResult(turnResult, buildIdleExpansionValidationContext(state, opts, activeTurn));
105
115
  if (idleExpansionResult.errors.length > 0) {
106
116
  return result('schema', 'schema_error', idleExpansionResult.errors, idleExpansionResult.warnings);
@@ -468,6 +478,112 @@ function buildIdleExpansionValidationContext(state, opts, activeTurn) {
468
478
  };
469
479
  }
470
480
 
481
+ function maybeAttachIdleExpansionSidecar(root, stagingRel, turnResult, context) {
482
+ if (context.required !== true || turnResult?.idle_expansion_result !== undefined) {
483
+ return { turnResult, warnings: [] };
484
+ }
485
+
486
+ const sidecarRel = join(dirname(stagingRel), 'idle-expansion-result.json');
487
+ const sidecarAbs = join(root, sidecarRel);
488
+ if (!existsSync(sidecarAbs)) {
489
+ return { turnResult, warnings: [] };
490
+ }
491
+
492
+ let raw;
493
+ try {
494
+ raw = readFileSync(sidecarAbs, 'utf8');
495
+ } catch (err) {
496
+ return { turnResult, warnings: [`[normalized] Cannot read idle expansion sidecar ${sidecarRel}: ${err.message}`] };
497
+ }
498
+
499
+ let sidecar;
500
+ try {
501
+ sidecar = JSON.parse(raw);
502
+ } catch (err) {
503
+ return { turnResult, warnings: [`[normalized] Invalid JSON in idle expansion sidecar ${sidecarRel}: ${err.message}`] };
504
+ }
505
+
506
+ const idleExpansionResult = normalizeIdleExpansionSidecar(sidecar, context);
507
+ return {
508
+ turnResult: {
509
+ ...turnResult,
510
+ idle_expansion_result: idleExpansionResult,
511
+ },
512
+ warnings: [`[normalized] Loaded idle_expansion_result from ${sidecarRel}.`],
513
+ };
514
+ }
515
+
516
+ function normalizeIdleExpansionSidecar(sidecar, context) {
517
+ if (!sidecar || typeof sidecar !== 'object' || Array.isArray(sidecar)) {
518
+ return sidecar;
519
+ }
520
+
521
+ const result = {
522
+ ...sidecar,
523
+ expansion_iteration: Number.isInteger(sidecar.expansion_iteration)
524
+ ? sidecar.expansion_iteration
525
+ : context.expansionIteration,
526
+ };
527
+
528
+ const intent = sidecar.new_intake_intent || sidecar.proposed_intent;
529
+ if (sidecar.kind === 'new_intake_intent' && intent && typeof intent === 'object' && !Array.isArray(intent)) {
530
+ result.new_intake_intent = {
531
+ title: intent.title,
532
+ charter: intent.charter,
533
+ acceptance_contract: intent.acceptance_contract,
534
+ priority: intent.priority,
535
+ template: intent.template,
536
+ };
537
+ result.vision_traceability = normalizeVisionTraceabilityForTurnResult(
538
+ sidecar.vision_traceability || intent.vision_traceability,
539
+ );
540
+ } else if (sidecar.vision_traceability !== undefined) {
541
+ result.vision_traceability = normalizeVisionTraceabilityForTurnResult(sidecar.vision_traceability);
542
+ }
543
+
544
+ if (
545
+ sidecar.kind === 'vision_exhausted'
546
+ && sidecar.vision_exhausted
547
+ && typeof sidecar.vision_exhausted === 'object'
548
+ && !Array.isArray(sidecar.vision_exhausted)
549
+ && Array.isArray(sidecar.vision_exhausted.classification)
550
+ ) {
551
+ result.vision_exhausted = {
552
+ ...sidecar.vision_exhausted,
553
+ classification: sidecar.vision_exhausted.classification.map((entry) => {
554
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
555
+ return entry;
556
+ }
557
+ return {
558
+ ...entry,
559
+ vision_heading: entry.vision_heading || entry.heading,
560
+ };
561
+ }),
562
+ };
563
+ }
564
+
565
+ return normalizeIdleExpansionMutualExclusionSentinel(result).value;
566
+ }
567
+
568
+ function normalizeVisionTraceabilityForTurnResult(traceability) {
569
+ if (!Array.isArray(traceability)) {
570
+ return traceability;
571
+ }
572
+
573
+ return traceability.map((entry) => {
574
+ if (typeof entry === 'string') {
575
+ return { vision_heading: entry };
576
+ }
577
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
578
+ return entry;
579
+ }
580
+ return {
581
+ ...entry,
582
+ vision_heading: entry.vision_heading || entry.heading,
583
+ };
584
+ });
585
+ }
586
+
471
587
  // ── Stage B: Assignment Validation ───────────────────────────────────────────
472
588
 
473
589
  function validateAssignment(tr, state) {
@@ -904,6 +1020,14 @@ export function normalizeTurnResult(tr, config, context = {}) {
904
1020
  normalized.artifacts_created = coerced;
905
1021
  }
906
1022
 
1023
+ const idleExpansionCleanup = normalizeIdleExpansionMutualExclusionSentinel(
1024
+ normalized.idle_expansion_result,
1025
+ );
1026
+ if (idleExpansionCleanup.changed) {
1027
+ normalized.idle_expansion_result = idleExpansionCleanup.value;
1028
+ corrections.push(idleExpansionCleanup.correction);
1029
+ }
1030
+
907
1031
  // ── Rule 2: exit-gate-as-phase auto-correction ────────────────────────
908
1032
  const gates = config?.gates;
909
1033
  if (
@@ -1057,6 +1181,28 @@ export function normalizeTurnResult(tr, config, context = {}) {
1057
1181
  return { normalized, corrections };
1058
1182
  }
1059
1183
 
1184
+ function normalizeIdleExpansionMutualExclusionSentinel(result) {
1185
+ if (!result || typeof result !== 'object' || Array.isArray(result)) {
1186
+ return { changed: false, value: result, correction: '' };
1187
+ }
1188
+
1189
+ if (
1190
+ result.kind === 'new_intake_intent'
1191
+ && ('vision_exhausted' in result)
1192
+ && (result.vision_exhausted === false || result.vision_exhausted === null)
1193
+ ) {
1194
+ const normalized = { ...result };
1195
+ delete normalized.vision_exhausted;
1196
+ return {
1197
+ changed: true,
1198
+ value: normalized,
1199
+ correction: 'idle_expansion_result.vision_exhausted: removed false sentinel for new_intake_intent',
1200
+ };
1201
+ }
1202
+
1203
+ return { changed: false, value: result, correction: '' };
1204
+ }
1205
+
1060
1206
  // ── Helpers ──────────────────────────────────────────────────────────────────
1061
1207
 
1062
1208
  function result(stage, errorClass, errors, warnings = []) {