agentxchain 2.131.0 → 2.132.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
package/scripts/release-bump.sh
CHANGED
|
@@ -82,6 +82,9 @@ ALLOWED_RELEASE_PATHS=(
|
|
|
82
82
|
".planning/MARKETING/REDDIT_POSTS.md"
|
|
83
83
|
".planning/MARKETING/HN_SUBMISSION.md"
|
|
84
84
|
"website-v2/static/llms.txt"
|
|
85
|
+
"website-v2/docs/getting-started.mdx"
|
|
86
|
+
"website-v2/docs/quickstart.mdx"
|
|
87
|
+
"website-v2/docs/five-minute-tutorial.mdx"
|
|
85
88
|
"cli/homebrew/agentxchain.rb"
|
|
86
89
|
"cli/homebrew/README.md"
|
|
87
90
|
)
|
package/src/commands/events.js
CHANGED
|
@@ -65,6 +65,9 @@ function printEvent(evt) {
|
|
|
65
65
|
const conflictDetail = evt.event_type === 'turn_conflicted'
|
|
66
66
|
? ` — ${formatConflictDetail(evt)}`
|
|
67
67
|
: '';
|
|
68
|
+
const conflictResolvedDetail = evt.event_type === 'conflict_resolved'
|
|
69
|
+
? ` — ${formatConflictResolvedDetail(evt)}`
|
|
70
|
+
: '';
|
|
68
71
|
const rejectionDetail = evt.event_type === 'turn_rejected' && evt.payload?.reason
|
|
69
72
|
? ` — ${evt.payload.reason}${evt.payload.failed_stage ? ` (${evt.payload.failed_stage})` : ''}`
|
|
70
73
|
: '';
|
|
@@ -82,7 +85,10 @@ function printEvent(evt) {
|
|
|
82
85
|
: evt.event_type === 'human_escalation_resolved' && evt.payload?.escalation_id
|
|
83
86
|
? ` ${evt.payload.escalation_id} via ${evt.payload.resolved_via || '?'}`
|
|
84
87
|
: '';
|
|
85
|
-
|
|
88
|
+
const coordinatorRetryDetail = evt.event_type === 'coordinator_retry' && evt.payload
|
|
89
|
+
? ` — ws ${evt.payload.workstream_id || '?'} repo ${evt.payload.repo_id || '?'} (retry of ${evt.payload.failed_turn_id || '?'})`
|
|
90
|
+
: '';
|
|
91
|
+
console.log(`${chalk.dim(ts)} ${type} ${chalk.cyan(runId)} ${phase}${turnInfo}${intentInfo}${conflictDetail}${conflictResolvedDetail}${rejectionDetail}${acceptanceFailedDetail}${phaseTransitionDetail}${gateFailedDetail}${humanEscalationDetail}${coordinatorRetryDetail}`);
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
function formatConflictDetail(evt) {
|
|
@@ -105,6 +111,16 @@ function formatConflictDetail(evt) {
|
|
|
105
111
|
return parts.filter(Boolean).join(' | ');
|
|
106
112
|
}
|
|
107
113
|
|
|
114
|
+
function formatConflictResolvedDetail(evt) {
|
|
115
|
+
const payload = evt.payload || {};
|
|
116
|
+
const fileSummary = summarizeList(payload.conflicting_files, 3) || 'resolved conflict';
|
|
117
|
+
const resolvedVia = payload.resolution ? `via ${payload.resolution}` : null;
|
|
118
|
+
const overlapRatio = typeof payload.overlap_ratio === 'number'
|
|
119
|
+
? `${Math.round(payload.overlap_ratio * 100)}% overlap`
|
|
120
|
+
: null;
|
|
121
|
+
return [fileSummary, resolvedVia, overlapRatio].filter(Boolean).join(' | ');
|
|
122
|
+
}
|
|
123
|
+
|
|
108
124
|
function summarizeList(items, limit) {
|
|
109
125
|
if (!Array.isArray(items) || items.length === 0) return '';
|
|
110
126
|
const shown = items.slice(0, limit).join(', ');
|
|
@@ -123,6 +139,7 @@ function colorEventType(type) {
|
|
|
123
139
|
acceptance_failed: chalk.red.bold,
|
|
124
140
|
turn_reissued: chalk.cyan,
|
|
125
141
|
turn_conflicted: chalk.redBright,
|
|
142
|
+
conflict_resolved: chalk.greenBright,
|
|
126
143
|
phase_entered: chalk.magenta,
|
|
127
144
|
escalation_raised: chalk.red.bold,
|
|
128
145
|
escalation_resolved: chalk.green,
|
|
@@ -132,6 +149,9 @@ function colorEventType(type) {
|
|
|
132
149
|
gate_approved: chalk.green,
|
|
133
150
|
gate_failed: chalk.red,
|
|
134
151
|
budget_exceeded_warn: chalk.yellowBright,
|
|
152
|
+
coordinator_retry: chalk.cyan.bold,
|
|
153
|
+
turn_checkpointed: chalk.green,
|
|
154
|
+
dispatch_progress: chalk.blue.dim,
|
|
135
155
|
};
|
|
136
156
|
const colorFn = colors[type] || chalk.white;
|
|
137
157
|
return colorFn(pad(type, 22));
|
|
@@ -1088,15 +1088,63 @@ function cleanupTurnArtifacts(root, turnId) {
|
|
|
1088
1088
|
} catch { /* best-effort */ }
|
|
1089
1089
|
}
|
|
1090
1090
|
|
|
1091
|
-
function
|
|
1091
|
+
function getWorkflowArtifactOwners(config, filePath) {
|
|
1092
|
+
const owners = new Set();
|
|
1093
|
+
const phases = config?.workflow_kit?.phases;
|
|
1094
|
+
if (!phases || typeof phases !== 'object') {
|
|
1095
|
+
return owners;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
for (const phaseConfig of Object.values(phases)) {
|
|
1099
|
+
const artifacts = Array.isArray(phaseConfig?.artifacts) ? phaseConfig.artifacts : [];
|
|
1100
|
+
for (const artifact of artifacts) {
|
|
1101
|
+
if (artifact?.path !== filePath) {
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
if (typeof artifact.owned_by === 'string' && artifact.owned_by.length > 0) {
|
|
1105
|
+
owners.add(artifact.owned_by);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
return owners;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
function isForwardRevisionFile(targetTurn, historyEntry, filePath, config) {
|
|
1114
|
+
if (!targetTurn || !historyEntry) {
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
if (historyEntry.role !== targetTurn.assigned_role) {
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const explicitOwners = getWorkflowArtifactOwners(config, filePath);
|
|
1122
|
+
if (explicitOwners.size > 0) {
|
|
1123
|
+
return explicitOwners.size === 1 && explicitOwners.has(targetTurn.assigned_role);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (!filePath.startsWith('.planning/')) {
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
return config?.routing?.planning?.entry_role === targetTurn.assigned_role;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
function classifyAcceptanceOverlap(targetTurn, conflictFiles, historyEntries, config) {
|
|
1092
1134
|
const observedFiles = [...new Set(Array.isArray(conflictFiles) ? conflictFiles : [])];
|
|
1093
1135
|
if (observedFiles.length === 0) {
|
|
1094
|
-
return
|
|
1136
|
+
return {
|
|
1137
|
+
conflict: null,
|
|
1138
|
+
forward_revision_files: [],
|
|
1139
|
+
forward_revision_turns: [],
|
|
1140
|
+
};
|
|
1095
1141
|
}
|
|
1096
1142
|
|
|
1097
1143
|
const observedFileSet = new Set(observedFiles);
|
|
1098
1144
|
const acceptedSince = [];
|
|
1099
1145
|
const conflictingFiles = new Set();
|
|
1146
|
+
const forwardRevisionFiles = new Set();
|
|
1147
|
+
const forwardRevisionTurns = new Map();
|
|
1100
1148
|
|
|
1101
1149
|
for (const entry of historyEntries) {
|
|
1102
1150
|
if ((entry.accepted_sequence || 0) <= (targetTurn.assigned_sequence || 0)) {
|
|
@@ -1108,35 +1156,77 @@ function detectAcceptanceConflict(targetTurn, conflictFiles, historyEntries) {
|
|
|
1108
1156
|
continue;
|
|
1109
1157
|
}
|
|
1110
1158
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1159
|
+
const destructiveFiles = [];
|
|
1160
|
+
const forwardFiles = [];
|
|
1161
|
+
for (const file of overlap) {
|
|
1162
|
+
if (isForwardRevisionFile(targetTurn, entry, file, config)) {
|
|
1163
|
+
forwardFiles.push(file);
|
|
1164
|
+
} else {
|
|
1165
|
+
destructiveFiles.push(file);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (destructiveFiles.length > 0) {
|
|
1170
|
+
destructiveFiles.forEach(file => conflictingFiles.add(file));
|
|
1171
|
+
acceptedSince.push({
|
|
1172
|
+
turn_id: entry.turn_id,
|
|
1173
|
+
role: entry.role,
|
|
1174
|
+
accepted_sequence: entry.accepted_sequence,
|
|
1175
|
+
files_changed: destructiveFiles,
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (forwardFiles.length > 0) {
|
|
1180
|
+
forwardFiles.forEach(file => forwardRevisionFiles.add(file));
|
|
1181
|
+
const existing = forwardRevisionTurns.get(entry.turn_id) || {
|
|
1182
|
+
turn_id: entry.turn_id,
|
|
1183
|
+
role: entry.role,
|
|
1184
|
+
accepted_sequence: entry.accepted_sequence,
|
|
1185
|
+
files_changed: [],
|
|
1186
|
+
};
|
|
1187
|
+
existing.files_changed = [...new Set([...existing.files_changed, ...forwardFiles])];
|
|
1188
|
+
forwardRevisionTurns.set(entry.turn_id, existing);
|
|
1189
|
+
}
|
|
1118
1190
|
}
|
|
1119
1191
|
|
|
1192
|
+
const forwardRevisionContext = {
|
|
1193
|
+
files: [...forwardRevisionFiles],
|
|
1194
|
+
accepted_since_turn_ids: [...forwardRevisionTurns.values()].map((entry) => entry.turn_id),
|
|
1195
|
+
accepted_since: [...forwardRevisionTurns.values()],
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1120
1198
|
if (acceptedSince.length === 0) {
|
|
1121
|
-
return
|
|
1199
|
+
return {
|
|
1200
|
+
conflict: null,
|
|
1201
|
+
forward_revision_files: forwardRevisionContext.files,
|
|
1202
|
+
forward_revision_turns: forwardRevisionContext.accepted_since,
|
|
1203
|
+
};
|
|
1122
1204
|
}
|
|
1123
1205
|
|
|
1124
1206
|
const conflicting = [...conflictingFiles];
|
|
1125
1207
|
const overlapRatio = observedFiles.length > 0 ? conflicting.length / observedFiles.length : 0;
|
|
1126
1208
|
|
|
1127
1209
|
return {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1210
|
+
conflict: {
|
|
1211
|
+
type: 'file_conflict',
|
|
1212
|
+
conflicting_turn: {
|
|
1213
|
+
turn_id: targetTurn.turn_id,
|
|
1214
|
+
role: targetTurn.assigned_role,
|
|
1215
|
+
attempt: targetTurn.attempt,
|
|
1216
|
+
files_changed: observedFiles,
|
|
1217
|
+
},
|
|
1218
|
+
accepted_since: acceptedSince,
|
|
1219
|
+
conflicting_files: conflicting,
|
|
1220
|
+
non_conflicting_files: observedFiles.filter(
|
|
1221
|
+
(file) => !conflictingFiles.has(file) && !forwardRevisionFiles.has(file),
|
|
1222
|
+
),
|
|
1223
|
+
forward_revision_files: forwardRevisionContext.files,
|
|
1224
|
+
forward_revision_turns: forwardRevisionContext.accepted_since,
|
|
1225
|
+
overlap_ratio: overlapRatio,
|
|
1226
|
+
suggested_resolution: overlapRatio < 0.5 ? 'reject_and_reassign' : 'human_merge',
|
|
1134
1227
|
},
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
non_conflicting_files: observedFiles.filter(file => !conflictingFiles.has(file)),
|
|
1138
|
-
overlap_ratio: overlapRatio,
|
|
1139
|
-
suggested_resolution: overlapRatio < 0.5 ? 'reject_and_reassign' : 'human_merge',
|
|
1228
|
+
forward_revision_files: forwardRevisionContext.files,
|
|
1229
|
+
forward_revision_turns: forwardRevisionContext.accepted_since,
|
|
1140
1230
|
};
|
|
1141
1231
|
}
|
|
1142
1232
|
|
|
@@ -2749,40 +2839,6 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
2749
2839
|
error_code: 'protocol_error',
|
|
2750
2840
|
};
|
|
2751
2841
|
}
|
|
2752
|
-
|
|
2753
|
-
if (currentTurn.conflict_state.status !== 'human_merging') {
|
|
2754
|
-
appendJsonl(root, LEDGER_PATH, {
|
|
2755
|
-
timestamp: new Date().toISOString(),
|
|
2756
|
-
decision: 'conflict_resolution_selected',
|
|
2757
|
-
turn_id: currentTurn.turn_id,
|
|
2758
|
-
attempt: currentTurn.attempt,
|
|
2759
|
-
role: currentTurn.assigned_role,
|
|
2760
|
-
phase: state.phase,
|
|
2761
|
-
conflict: {
|
|
2762
|
-
conflicting_files: currentTurn.conflict_state.conflict_error?.conflicting_files || [],
|
|
2763
|
-
accepted_since_turn_ids: (currentTurn.conflict_state.conflict_error?.accepted_since || []).map((entry) => entry.turn_id),
|
|
2764
|
-
overlap_ratio: currentTurn.conflict_state.conflict_error?.overlap_ratio ?? 0,
|
|
2765
|
-
},
|
|
2766
|
-
resolution_chosen: 'human_merge',
|
|
2767
|
-
});
|
|
2768
|
-
|
|
2769
|
-
state = {
|
|
2770
|
-
...state,
|
|
2771
|
-
active_turns: {
|
|
2772
|
-
...getActiveTurns(state),
|
|
2773
|
-
[currentTurn.turn_id]: {
|
|
2774
|
-
...currentTurn,
|
|
2775
|
-
status: 'conflicted',
|
|
2776
|
-
conflict_state: {
|
|
2777
|
-
...currentTurn.conflict_state,
|
|
2778
|
-
status: 'human_merging',
|
|
2779
|
-
},
|
|
2780
|
-
},
|
|
2781
|
-
},
|
|
2782
|
-
};
|
|
2783
|
-
writeState(root, state);
|
|
2784
|
-
currentTurn = state.active_turns[currentTurn.turn_id];
|
|
2785
|
-
}
|
|
2786
2842
|
}
|
|
2787
2843
|
|
|
2788
2844
|
const turnStagingPath = getTurnStagingResultPath(currentTurn.turn_id);
|
|
@@ -3142,11 +3198,29 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
3142
3198
|
};
|
|
3143
3199
|
}
|
|
3144
3200
|
|
|
3145
|
-
const
|
|
3201
|
+
const overlapClassification = classifyAcceptanceOverlap(
|
|
3146
3202
|
currentTurn,
|
|
3147
3203
|
buildConflictCandidateFiles(rawObservation, observation, turnResult.files_changed || []),
|
|
3148
3204
|
historyEntries,
|
|
3205
|
+
config,
|
|
3149
3206
|
);
|
|
3207
|
+
const forwardRevision = overlapClassification.forward_revision_files.length > 0
|
|
3208
|
+
? {
|
|
3209
|
+
files: overlapClassification.forward_revision_files,
|
|
3210
|
+
accepted_since_turn_ids: overlapClassification.forward_revision_turns.map((entry) => entry.turn_id),
|
|
3211
|
+
accepted_since: overlapClassification.forward_revision_turns,
|
|
3212
|
+
}
|
|
3213
|
+
: null;
|
|
3214
|
+
const conflict = resolutionMode === 'human_merge' ? null : overlapClassification.conflict;
|
|
3215
|
+
const conflictResolution = resolutionMode === 'human_merge'
|
|
3216
|
+
? {
|
|
3217
|
+
mode: 'human_merge',
|
|
3218
|
+
merge_strategy: 'operator_authoritative_staged_result',
|
|
3219
|
+
conflicting_files: currentTurn.conflict_state?.conflict_error?.conflicting_files || [],
|
|
3220
|
+
accepted_since_turn_ids: (currentTurn.conflict_state?.conflict_error?.accepted_since || []).map((entry) => entry.turn_id),
|
|
3221
|
+
overlap_ratio: currentTurn.conflict_state?.conflict_error?.overlap_ratio ?? 0,
|
|
3222
|
+
}
|
|
3223
|
+
: null;
|
|
3150
3224
|
|
|
3151
3225
|
if (conflict) {
|
|
3152
3226
|
const detectionCount = (currentTurn.conflict_state?.detection_count || 0) + 1;
|
|
@@ -3301,6 +3375,8 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
3301
3375
|
assigned_sequence: Number.isInteger(currentTurn.assigned_sequence) ? currentTurn.assigned_sequence : acceptedSequence,
|
|
3302
3376
|
accepted_sequence: acceptedSequence,
|
|
3303
3377
|
concurrent_with: Array.isArray(currentTurn.concurrent_with) ? currentTurn.concurrent_with : [],
|
|
3378
|
+
...(forwardRevision ? { forward_revision: forwardRevision } : {}),
|
|
3379
|
+
...(conflictResolution ? { conflict_resolution: conflictResolution } : {}),
|
|
3304
3380
|
cost: turnResult.cost || {},
|
|
3305
3381
|
...(currentTurn.started_at ? { started_at: currentTurn.started_at } : {}),
|
|
3306
3382
|
accepted_at: now,
|
|
@@ -3357,6 +3433,49 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
3357
3433
|
});
|
|
3358
3434
|
}
|
|
3359
3435
|
}
|
|
3436
|
+
if (forwardRevision) {
|
|
3437
|
+
ledgerEntries.push({
|
|
3438
|
+
timestamp: now,
|
|
3439
|
+
decision: 'forward_revision_accepted',
|
|
3440
|
+
turn_id: currentTurn.turn_id,
|
|
3441
|
+
attempt: currentTurn.attempt,
|
|
3442
|
+
role: currentTurn.assigned_role,
|
|
3443
|
+
phase: state.phase,
|
|
3444
|
+
forward_revision: {
|
|
3445
|
+
files: forwardRevision.files,
|
|
3446
|
+
accepted_since_turn_ids: forwardRevision.accepted_since_turn_ids,
|
|
3447
|
+
},
|
|
3448
|
+
});
|
|
3449
|
+
}
|
|
3450
|
+
if (conflictResolution) {
|
|
3451
|
+
const conflictSummary = {
|
|
3452
|
+
conflicting_files: conflictResolution.conflicting_files,
|
|
3453
|
+
accepted_since_turn_ids: conflictResolution.accepted_since_turn_ids,
|
|
3454
|
+
overlap_ratio: conflictResolution.overlap_ratio,
|
|
3455
|
+
};
|
|
3456
|
+
ledgerEntries.push({
|
|
3457
|
+
timestamp: now,
|
|
3458
|
+
decision: 'conflict_resolution_selected',
|
|
3459
|
+
turn_id: currentTurn.turn_id,
|
|
3460
|
+
attempt: currentTurn.attempt,
|
|
3461
|
+
role: currentTurn.assigned_role,
|
|
3462
|
+
phase: state.phase,
|
|
3463
|
+
conflict: conflictSummary,
|
|
3464
|
+
resolution_chosen: conflictResolution.mode,
|
|
3465
|
+
merge_strategy: conflictResolution.merge_strategy,
|
|
3466
|
+
});
|
|
3467
|
+
ledgerEntries.push({
|
|
3468
|
+
timestamp: now,
|
|
3469
|
+
decision: 'conflict_resolved',
|
|
3470
|
+
turn_id: currentTurn.turn_id,
|
|
3471
|
+
attempt: currentTurn.attempt,
|
|
3472
|
+
role: currentTurn.assigned_role,
|
|
3473
|
+
phase: state.phase,
|
|
3474
|
+
conflict: conflictSummary,
|
|
3475
|
+
resolution_chosen: conflictResolution.mode,
|
|
3476
|
+
merge_strategy: conflictResolution.merge_strategy,
|
|
3477
|
+
});
|
|
3478
|
+
}
|
|
3360
3479
|
|
|
3361
3480
|
const turnNumber = turnResult.turn_id.replace(/^turn_/, '').slice(0, 8);
|
|
3362
3481
|
const talkSection = `## Turn ${turnNumber} — ${turnResult.role} (${state.phase})\n\n- **Status:** ${turnResult.status}\n- **Summary:** ${turnResult.summary}\n${turnResult.decisions?.length ? turnResult.decisions.map(d => `- **Decision ${d.id}:** ${d.statement}`).join('\n') + '\n' : ''}${turnResult.objections?.length ? turnResult.objections.map(o => `- **Objection ${o.id} (${o.severity}):** ${o.statement}`).join('\n') + '\n' : ''}- **Proposed next:** ${turnResult.proposed_next_role || 'human'}\n\n---\n`;
|
|
@@ -4107,6 +4226,22 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
4107
4226
|
intent_id: currentTurn.intake_context?.intent_id || null,
|
|
4108
4227
|
payload: turnAcceptedPayload,
|
|
4109
4228
|
});
|
|
4229
|
+
if (conflictResolution) {
|
|
4230
|
+
emitRunEvent(root, 'conflict_resolved', {
|
|
4231
|
+
run_id: updatedState.run_id,
|
|
4232
|
+
phase: updatedState.phase,
|
|
4233
|
+
status: updatedState.status,
|
|
4234
|
+
turn: { turn_id: currentTurn.turn_id, role_id: currentTurn.assigned_role },
|
|
4235
|
+
intent_id: currentTurn.intake_context?.intent_id || null,
|
|
4236
|
+
payload: {
|
|
4237
|
+
resolution: conflictResolution.mode,
|
|
4238
|
+
merge_strategy: conflictResolution.merge_strategy,
|
|
4239
|
+
conflicting_files: conflictResolution.conflicting_files,
|
|
4240
|
+
accepted_since_turn_ids: conflictResolution.accepted_since_turn_ids,
|
|
4241
|
+
overlap_ratio: conflictResolution.overlap_ratio,
|
|
4242
|
+
},
|
|
4243
|
+
});
|
|
4244
|
+
}
|
|
4110
4245
|
|
|
4111
4246
|
if (updatedState.status === 'blocked') {
|
|
4112
4247
|
// DEC-RHTR-SPEC: Record blocked outcome in cross-run history (non-fatal)
|
|
@@ -36,6 +36,21 @@ function describeEvent(eventType, entry) {
|
|
|
36
36
|
case 'gate_approved':
|
|
37
37
|
case 'gate_failed':
|
|
38
38
|
return `${prefix}${eventType}${gateId ? ` (${gateId})` : ''}`;
|
|
39
|
+
case 'turn_conflicted':
|
|
40
|
+
return `${prefix}${eventType}${roleId ? ` [${roleId}]` : ''}`;
|
|
41
|
+
case 'conflict_resolved': {
|
|
42
|
+
const resolution = trimToNull(entry.payload?.resolution);
|
|
43
|
+
return `${prefix}${eventType}${roleId ? ` [${roleId}]` : ''}${resolution ? ` via ${resolution}` : ''}`;
|
|
44
|
+
}
|
|
45
|
+
case 'coordinator_retry': {
|
|
46
|
+
const wsId = trimToNull(entry.payload?.workstream_id);
|
|
47
|
+
const retryRepo = trimToNull(entry.payload?.repo_id);
|
|
48
|
+
return `${prefix}${eventType}${wsId ? ` ${wsId}` : ''}${retryRepo ? ` (${retryRepo})` : ''}`;
|
|
49
|
+
}
|
|
50
|
+
case 'turn_checkpointed':
|
|
51
|
+
return `${prefix}${eventType}${roleId ? ` [${roleId}]` : ''}`;
|
|
52
|
+
case 'dispatch_progress':
|
|
53
|
+
return `${prefix}${eventType}${roleId ? ` [${roleId}]` : ''}`;
|
|
39
54
|
case 'run_blocked':
|
|
40
55
|
case 'run_completed':
|
|
41
56
|
case 'run_started':
|
|
@@ -22,6 +22,12 @@ export function formatCount(value) {
|
|
|
22
22
|
return new Intl.NumberFormat('en-US').format(value);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
const ONBOARDING_PREREQ_DOCS = [
|
|
26
|
+
'website-v2/docs/getting-started.mdx',
|
|
27
|
+
'website-v2/docs/quickstart.mdx',
|
|
28
|
+
'website-v2/docs/five-minute-tutorial.mdx',
|
|
29
|
+
];
|
|
30
|
+
|
|
25
31
|
function normalizeEvidenceText(value) {
|
|
26
32
|
return value
|
|
27
33
|
.replace(/^\s*-\s*/, '')
|
|
@@ -137,6 +143,28 @@ function validateTextIncludesVersionAndEvidence(relativePath, label) {
|
|
|
137
143
|
};
|
|
138
144
|
}
|
|
139
145
|
|
|
146
|
+
function validateOnboardingPrereqs(ctx, repoRoot) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
const requiredTokens = [
|
|
149
|
+
`Minimum CLI version: \`agentxchain ${ctx.targetVersion}\` or newer`,
|
|
150
|
+
'agentxchain --version',
|
|
151
|
+
'npm install -g agentxchain@latest',
|
|
152
|
+
'brew upgrade agentxchain',
|
|
153
|
+
'npx --yes -p agentxchain@latest -c "agentxchain <command>"',
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const relativePath of ONBOARDING_PREREQ_DOCS) {
|
|
157
|
+
const content = read(repoRoot, relativePath);
|
|
158
|
+
for (const token of requiredTokens) {
|
|
159
|
+
if (!content.includes(token)) {
|
|
160
|
+
errors.push(`${relativePath} must include: ${token}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return errors;
|
|
166
|
+
}
|
|
167
|
+
|
|
140
168
|
export const RELEASE_ALIGNMENT_SURFACES = [
|
|
141
169
|
{
|
|
142
170
|
id: 'changelog',
|
|
@@ -274,6 +302,12 @@ export const RELEASE_ALIGNMENT_SURFACES = [
|
|
|
274
302
|
: [`website-v2/static/llms.txt must list ${ctx.releaseRoute}`];
|
|
275
303
|
},
|
|
276
304
|
},
|
|
305
|
+
{
|
|
306
|
+
id: 'onboarding_prereqs',
|
|
307
|
+
label: 'onboarding docs CLI-version prerequisites',
|
|
308
|
+
scopes: [RELEASE_ALIGNMENT_SCOPES.PREBUMP, RELEASE_ALIGNMENT_SCOPES.CURRENT],
|
|
309
|
+
check: validateOnboardingPrereqs,
|
|
310
|
+
},
|
|
277
311
|
{
|
|
278
312
|
id: 'homebrew_formula_url',
|
|
279
313
|
label: 'homebrew mirror formula url',
|