agentxchain 2.12.0 → 2.13.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/README.md CHANGED
@@ -91,6 +91,19 @@ agentxchain approve-completion
91
91
 
92
92
  Default governed scaffolding configures QA as `api_proxy` with `ANTHROPIC_API_KEY`. For a provider-free walkthrough, switch the QA runtime to `manual` before the QA step. If you override the dev runtime, either include `{prompt}` for argv delivery or set `--dev-prompt-transport` explicitly.
93
93
 
94
+ ### Multi-repo coordination
95
+
96
+ For initiatives spanning multiple governed repos, use the coordinator to add cross-repo sequencing and shared gates:
97
+
98
+ ```bash
99
+ npx agentxchain init --governed --template api-service --dir repos/backend -y
100
+ npx agentxchain init --governed --template web-app --dir repos/frontend -y
101
+ agentxchain multi init
102
+ agentxchain multi step --repo backend --role pm
103
+ ```
104
+
105
+ See the [multi-repo quickstart](https://agentxchain.dev/docs/quickstart#multi-repo-cold-start) for the full cold-start walkthrough.
106
+
94
107
  ### Migrate a legacy project
95
108
 
96
109
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxchain",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -66,6 +66,16 @@ function readRepoLocalHistory(repoPath) {
66
66
  }
67
67
  }
68
68
 
69
+ function isAcceptedRepoHistoryEntry(entry) {
70
+ if (!entry || typeof entry !== 'object') {
71
+ return false;
72
+ }
73
+
74
+ // Real governed history records the turn outcome in `status` and acceptance
75
+ // via `accepted_at`. Older coordinator fixtures used `status: "accepted"`.
76
+ return Boolean(entry.accepted_at) || entry.status === 'accepted';
77
+ }
78
+
69
79
  // ── Divergence Detection ────────────────────────────────────────────────────
70
80
 
71
81
  /**
@@ -166,7 +176,7 @@ export function detectDivergence(workspacePath, state, config) {
166
176
  // Read repo-local history to determine what happened
167
177
  const repoHistory = readRepoLocalHistory(repo.resolved_path);
168
178
  const turnAccepted = repoHistory.some(
169
- e => e?.turn_id === dispatch.repo_turn_id && e?.status === 'accepted'
179
+ e => e?.turn_id === dispatch.repo_turn_id && isAcceptedRepoHistoryEntry(e)
170
180
  );
171
181
  const turnRejected = repoHistory.some(
172
182
  e => e?.turn_id === dispatch.repo_turn_id && e?.status === 'rejected'
@@ -279,7 +289,7 @@ export function resyncFromRepoAuthority(workspacePath, state, config) {
279
289
 
280
290
  const repoHistory = readRepoLocalHistory(repo.resolved_path);
281
291
  const acceptedEntry = repoHistory.find(
282
- e => e?.turn_id === dispatch.repo_turn_id && e?.status === 'accepted'
292
+ e => e?.turn_id === dispatch.repo_turn_id && isAcceptedRepoHistoryEntry(e)
283
293
  );
284
294
 
285
295
  if (acceptedEntry) {
@@ -1,7 +1,7 @@
1
1
  import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, unlinkSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { tmpdir } from 'node:os';
4
- import { evaluatePhaseExit } from './gate-evaluator.js';
4
+ import { evaluatePhaseExit, evaluateRunCompletion } from './gate-evaluator.js';
5
5
  import {
6
6
  approvePhaseTransition,
7
7
  approveRunCompletion,
@@ -708,6 +708,51 @@ function executeFixtureOperation(workspace, fixture) {
708
708
  };
709
709
  }
710
710
 
711
+ case 'evaluate_run_completion': {
712
+ const state = readJson(join(root, '.agentxchain', 'state.json'));
713
+ const acceptedTurn = {
714
+ run_completion_request: fixture.setup.turn_result?.run_completion_request ?? true,
715
+ verification: fixture.setup.turn_result?.verification || { status: 'pass' },
716
+ };
717
+ const result = evaluateRunCompletion({
718
+ state,
719
+ config: fixtureConfig,
720
+ acceptedTurn,
721
+ root,
722
+ });
723
+
724
+ if (result.action === 'awaiting_human_approval') {
725
+ return {
726
+ result: 'success',
727
+ action: result.action,
728
+ new_status: 'paused',
729
+ pending_run_completion: {
730
+ phase: state.phase,
731
+ gate: result.gate_id,
732
+ },
733
+ };
734
+ }
735
+
736
+ if (result.action === 'complete') {
737
+ return {
738
+ result: 'success',
739
+ action: result.action,
740
+ new_status: 'completed',
741
+ };
742
+ }
743
+
744
+ return {
745
+ result: 'success',
746
+ action: result.action,
747
+ state_unchanged: true,
748
+ reason: result.missing_files.length > 0
749
+ ? 'requires_files predicate failed'
750
+ : result.missing_verification
751
+ ? 'requires_verification_pass predicate failed'
752
+ : (result.reasons[0] || null),
753
+ };
754
+ }
755
+
711
756
  case 'append_decision': {
712
757
  const ledgerPath = join(root, '.agentxchain', 'decision-ledger.jsonl');
713
758
  const existingLedger = readJsonl(ledgerPath);