agentxchain 0.8.8 → 2.1.1
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 +126 -142
- package/bin/agentxchain.js +186 -5
- package/dashboard/app.js +305 -0
- package/dashboard/components/blocked.js +145 -0
- package/dashboard/components/cross-repo.js +126 -0
- package/dashboard/components/gate.js +311 -0
- package/dashboard/components/hooks.js +177 -0
- package/dashboard/components/initiative.js +147 -0
- package/dashboard/components/ledger.js +165 -0
- package/dashboard/components/timeline.js +222 -0
- package/dashboard/index.html +352 -0
- package/package.json +14 -6
- package/scripts/live-api-proxy-preflight-smoke.sh +531 -0
- package/scripts/publish-from-tag.sh +88 -0
- package/scripts/release-postflight.sh +231 -0
- package/scripts/release-preflight.sh +167 -0
- package/src/commands/accept-turn.js +160 -0
- package/src/commands/approve-completion.js +80 -0
- package/src/commands/approve-transition.js +85 -0
- package/src/commands/dashboard.js +70 -0
- package/src/commands/init.js +516 -0
- package/src/commands/migrate.js +348 -0
- package/src/commands/multi.js +549 -0
- package/src/commands/plugin.js +157 -0
- package/src/commands/reject-turn.js +204 -0
- package/src/commands/resume.js +389 -0
- package/src/commands/status.js +196 -3
- package/src/commands/step.js +947 -0
- package/src/commands/template-list.js +33 -0
- package/src/commands/template-set.js +279 -0
- package/src/commands/validate.js +20 -11
- package/src/commands/verify.js +71 -0
- package/src/lib/adapters/api-proxy-adapter.js +1076 -0
- package/src/lib/adapters/local-cli-adapter.js +337 -0
- package/src/lib/adapters/manual-adapter.js +169 -0
- package/src/lib/blocked-state.js +94 -0
- package/src/lib/config.js +97 -1
- package/src/lib/context-compressor.js +121 -0
- package/src/lib/context-section-parser.js +220 -0
- package/src/lib/coordinator-acceptance.js +428 -0
- package/src/lib/coordinator-config.js +461 -0
- package/src/lib/coordinator-dispatch.js +276 -0
- package/src/lib/coordinator-gates.js +487 -0
- package/src/lib/coordinator-hooks.js +239 -0
- package/src/lib/coordinator-recovery.js +523 -0
- package/src/lib/coordinator-state.js +365 -0
- package/src/lib/cross-repo-context.js +247 -0
- package/src/lib/dashboard/bridge-server.js +284 -0
- package/src/lib/dashboard/file-watcher.js +93 -0
- package/src/lib/dashboard/state-reader.js +96 -0
- package/src/lib/dispatch-bundle.js +568 -0
- package/src/lib/dispatch-manifest.js +252 -0
- package/src/lib/gate-evaluator.js +285 -0
- package/src/lib/governed-state.js +2139 -0
- package/src/lib/governed-templates.js +145 -0
- package/src/lib/hook-runner.js +788 -0
- package/src/lib/normalized-config.js +539 -0
- package/src/lib/plugin-config-schema.js +192 -0
- package/src/lib/plugins.js +692 -0
- package/src/lib/protocol-conformance.js +291 -0
- package/src/lib/reference-conformance-adapter.js +717 -0
- package/src/lib/repo-observer.js +597 -0
- package/src/lib/repo.js +0 -31
- package/src/lib/schema.js +121 -0
- package/src/lib/schemas/turn-result.schema.json +205 -0
- package/src/lib/token-budget.js +206 -0
- package/src/lib/token-counter.js +27 -0
- package/src/lib/turn-paths.js +67 -0
- package/src/lib/turn-result-validator.js +496 -0
- package/src/lib/validation.js +137 -0
- package/src/templates/governed/api-service.json +31 -0
- package/src/templates/governed/cli-tool.json +30 -0
- package/src/templates/governed/generic.json +10 -0
- package/src/templates/governed/web-app.json +30 -0
package/src/commands/status.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { loadConfig, loadLock, loadState } from '../lib/config.js';
|
|
2
|
+
import { loadConfig, loadLock, loadProjectContext, loadProjectState, loadState } from '../lib/config.js';
|
|
3
|
+
import { deriveRecoveryDescriptor } from '../lib/blocked-state.js';
|
|
4
|
+
import { getActiveTurn, getActiveTurnCount, getActiveTurns } from '../lib/governed-state.js';
|
|
3
5
|
|
|
4
6
|
export async function statusCommand(opts) {
|
|
5
|
-
const
|
|
6
|
-
if (!
|
|
7
|
+
const context = loadProjectContext();
|
|
8
|
+
if (!context) {
|
|
7
9
|
console.log(chalk.red('No agentxchain.json found. Run `agentxchain init` first.'));
|
|
8
10
|
process.exit(1);
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
if (context.config.protocol_mode === 'governed') {
|
|
14
|
+
return renderGovernedStatus(context, opts);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const result = loadConfig();
|
|
11
18
|
const { root, config } = result;
|
|
12
19
|
const lock = loadLock(root);
|
|
13
20
|
const state = loadState(root);
|
|
@@ -64,11 +71,192 @@ export async function statusCommand(opts) {
|
|
|
64
71
|
console.log('');
|
|
65
72
|
}
|
|
66
73
|
|
|
74
|
+
function renderGovernedStatus(context, opts) {
|
|
75
|
+
const { root, config, version } = context;
|
|
76
|
+
const state = loadProjectState(root, config);
|
|
77
|
+
|
|
78
|
+
if (opts.json) {
|
|
79
|
+
console.log(JSON.stringify({
|
|
80
|
+
version,
|
|
81
|
+
protocol_mode: config.protocol_mode,
|
|
82
|
+
template: config.template || 'generic',
|
|
83
|
+
config,
|
|
84
|
+
state,
|
|
85
|
+
}, null, 2));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk.bold(' AgentXchain Status'));
|
|
91
|
+
console.log(chalk.dim(' ' + '─'.repeat(44)));
|
|
92
|
+
console.log('');
|
|
93
|
+
|
|
94
|
+
console.log(` ${chalk.dim('Project:')} ${config.project.name}`);
|
|
95
|
+
console.log(` ${chalk.dim('Protocol:')} ${chalk.cyan(`governed (v${version})`)}`);
|
|
96
|
+
console.log(` ${chalk.dim('Template:')} ${config.template || 'generic'}`);
|
|
97
|
+
console.log(` ${chalk.dim('Phase:')} ${state?.phase ? formatGovernedPhase(state.phase) : chalk.dim('unknown')}`);
|
|
98
|
+
console.log(` ${chalk.dim('Run:')} ${formatRunStatus(state?.status)}`);
|
|
99
|
+
if (state?.accepted_integration_ref) {
|
|
100
|
+
console.log(` ${chalk.dim('Accepted:')} ${state.accepted_integration_ref}`);
|
|
101
|
+
}
|
|
102
|
+
console.log('');
|
|
103
|
+
|
|
104
|
+
const activeTurnCount = getActiveTurnCount(state);
|
|
105
|
+
const activeTurns = getActiveTurns(state);
|
|
106
|
+
const singleActiveTurn = getActiveTurn(state);
|
|
107
|
+
if (activeTurnCount > 1) {
|
|
108
|
+
console.log(` ${chalk.dim('Turns:')} ${activeTurnCount} active`);
|
|
109
|
+
for (const turn of Object.values(activeTurns)) {
|
|
110
|
+
const marker = turn.status === 'conflicted'
|
|
111
|
+
? chalk.red('✗')
|
|
112
|
+
: chalk.yellow('●');
|
|
113
|
+
const statusLabel = turn.status === 'conflicted'
|
|
114
|
+
? chalk.red('conflicted')
|
|
115
|
+
: turn.status;
|
|
116
|
+
console.log(` ${marker} ${turn.turn_id} — ${chalk.bold(turn.assigned_role)} (${statusLabel}) [attempt ${turn.attempt}]`);
|
|
117
|
+
if (turn.status === 'conflicted' && turn.conflict_state) {
|
|
118
|
+
const cs = turn.conflict_state;
|
|
119
|
+
const files = cs.conflict_error?.conflicting_files || [];
|
|
120
|
+
const count = cs.detection_count || 1;
|
|
121
|
+
console.log(` ${chalk.dim('Conflict:')} ${files.length} file(s) — detection #${count}`);
|
|
122
|
+
if (cs.conflict_error?.overlap_ratio != null) {
|
|
123
|
+
console.log(` ${chalk.dim('Overlap:')} ${(cs.conflict_error.overlap_ratio * 100).toFixed(0)}%`);
|
|
124
|
+
}
|
|
125
|
+
const suggestion = cs.conflict_error?.suggested_resolution || 'reject_and_reassign';
|
|
126
|
+
console.log(` ${chalk.dim('Suggested:')} ${suggestion}`);
|
|
127
|
+
console.log(` ${chalk.dim('Resolve:')} ${chalk.cyan(`agentxchain reject-turn --turn ${turn.turn_id} --reassign`)}`);
|
|
128
|
+
console.log(` ${chalk.dim(' or:')} ${chalk.cyan(`agentxchain accept-turn --turn ${turn.turn_id} --resolution human_merge`)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} else if (singleActiveTurn) {
|
|
132
|
+
console.log(` ${chalk.dim('Turn:')} ${singleActiveTurn.turn_id}`);
|
|
133
|
+
console.log(` ${chalk.dim('Role:')} ${chalk.bold(singleActiveTurn.assigned_role)} (${singleActiveTurn.status})`);
|
|
134
|
+
console.log(` ${chalk.dim('Runtime:')} ${singleActiveTurn.runtime_id}`);
|
|
135
|
+
console.log(` ${chalk.dim('Attempt:')} ${singleActiveTurn.attempt}`);
|
|
136
|
+
if (singleActiveTurn.status === 'conflicted' && singleActiveTurn.conflict_state) {
|
|
137
|
+
const cs = singleActiveTurn.conflict_state;
|
|
138
|
+
const files = cs.conflict_error?.conflicting_files || [];
|
|
139
|
+
console.log(` ${chalk.dim('Conflict:')} ${chalk.red(`${files.length} file(s) conflicting`)} — detection #${cs.detection_count || 1}`);
|
|
140
|
+
console.log(` ${chalk.dim('Resolve:')} ${chalk.cyan('agentxchain reject-turn --reassign')}`);
|
|
141
|
+
console.log(` ${chalk.dim(' or:')} ${chalk.cyan('agentxchain accept-turn --resolution human_merge')}`);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
console.log(` ${chalk.dim('Turn:')} ${chalk.yellow('No active turn')}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Queued phase/completion requests
|
|
148
|
+
if (state?.queued_phase_transition) {
|
|
149
|
+
const qt = state.queued_phase_transition;
|
|
150
|
+
console.log('');
|
|
151
|
+
console.log(` ${chalk.dim('Queued:')} Phase transition ${formatGovernedPhase(qt.from)} → ${formatGovernedPhase(qt.to)} (awaiting drain)`);
|
|
152
|
+
}
|
|
153
|
+
if (state?.queued_run_completion) {
|
|
154
|
+
console.log('');
|
|
155
|
+
console.log(` ${chalk.dim('Queued:')} Run completion (awaiting drain)`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Per-turn budget reservations
|
|
159
|
+
if (state?.budget_reservations && Object.keys(state.budget_reservations).length > 0) {
|
|
160
|
+
console.log('');
|
|
161
|
+
console.log(` ${chalk.dim('Budget reservations:')}`);
|
|
162
|
+
for (const [turnId, reservation] of Object.entries(state.budget_reservations)) {
|
|
163
|
+
const amt = reservation.reserved_usd != null ? `$${formatUsd(reservation.reserved_usd)}` : '(unknown)';
|
|
164
|
+
console.log(` ${chalk.dim('●')} ${turnId}: ${amt}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (state?.blocked_on) {
|
|
169
|
+
console.log('');
|
|
170
|
+
if (state.status === 'blocked') {
|
|
171
|
+
const recovery = deriveRecoveryDescriptor(state);
|
|
172
|
+
const detail = recovery?.detail || state.blocked_on;
|
|
173
|
+
console.log(` ${chalk.dim('Blocked:')} ${chalk.red.bold('BLOCKED')} — ${detail}`);
|
|
174
|
+
} else if (state.blocked_on.startsWith('human_approval:')) {
|
|
175
|
+
const gate = state.blocked_on.replace('human_approval:', '');
|
|
176
|
+
console.log(` ${chalk.dim('Blocked:')} ${chalk.yellow('AWAITING HUMAN APPROVAL')} — gate: ${chalk.bold(gate)}`);
|
|
177
|
+
} else {
|
|
178
|
+
console.log(` ${chalk.dim('Blocked:')} ${chalk.red(state.blocked_on)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const recovery = deriveRecoveryDescriptor(state);
|
|
183
|
+
if (recovery) {
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log(` ${chalk.dim('Reason:')} ${recovery.typed_reason}`);
|
|
186
|
+
console.log(` ${chalk.dim('Owner:')} ${recovery.owner}`);
|
|
187
|
+
console.log(` ${chalk.dim('Action:')} ${recovery.recovery_action}`);
|
|
188
|
+
console.log(` ${chalk.dim('Turn:')} ${recovery.turn_retained ? 'retained' : 'cleared'}`);
|
|
189
|
+
if (recovery.detail) {
|
|
190
|
+
console.log(` ${chalk.dim('Detail:')} ${recovery.detail}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (state?.pending_phase_transition) {
|
|
195
|
+
const pt = state.pending_phase_transition;
|
|
196
|
+
console.log(` ${chalk.dim('Pending:')} ${formatGovernedPhase(pt.from)} → ${formatGovernedPhase(pt.to)}`);
|
|
197
|
+
console.log(` ${chalk.dim('Gate:')} ${pt.gate} (requires human approval)`);
|
|
198
|
+
console.log(` ${chalk.dim('Action:')} Run ${chalk.cyan('agentxchain approve-transition')} to advance`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (state?.pending_run_completion) {
|
|
202
|
+
const pc = state.pending_run_completion;
|
|
203
|
+
console.log(` ${chalk.dim('Pending:')} ${chalk.bold('Run Completion')}`);
|
|
204
|
+
console.log(` ${chalk.dim('Gate:')} ${pc.gate} (requires human approval)`);
|
|
205
|
+
console.log(` ${chalk.dim('Action:')} Run ${chalk.cyan('agentxchain approve-completion')} to finalize`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (state?.status === 'completed') {
|
|
209
|
+
console.log('');
|
|
210
|
+
console.log(` ${chalk.green.bold('✓ Run completed')}`);
|
|
211
|
+
if (state.completed_at) {
|
|
212
|
+
console.log(` ${chalk.dim('Completed:')} ${state.completed_at}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (state?.phase_gate_status) {
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log(` ${chalk.dim('Gates:')}`);
|
|
219
|
+
for (const [gate, status] of Object.entries(state.phase_gate_status)) {
|
|
220
|
+
const icon = status === 'passed' ? chalk.green('✓') : chalk.dim('○');
|
|
221
|
+
console.log(` ${icon} ${gate}: ${status}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (state?.budget_status) {
|
|
226
|
+
console.log('');
|
|
227
|
+
console.log(` ${chalk.dim('Budget:')} spent $${formatUsd(state.budget_status.spent_usd)} / remaining $${formatUsd(state.budget_status.remaining_usd)}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
console.log('');
|
|
231
|
+
console.log(` ${chalk.dim('Roles:')} ${Object.keys(config.roles).length}`);
|
|
232
|
+
for (const [id, role] of Object.entries(config.roles)) {
|
|
233
|
+
const isAssigned = Object.values(getActiveTurns(state)).some(turn => turn.assigned_role === id);
|
|
234
|
+
const marker = isAssigned ? chalk.yellow('●') : chalk.dim('○');
|
|
235
|
+
const label = isAssigned ? chalk.bold(id) : id;
|
|
236
|
+
console.log(` ${marker} ${label} — ${role.title} [${role.write_authority}]`);
|
|
237
|
+
}
|
|
238
|
+
console.log('');
|
|
239
|
+
}
|
|
240
|
+
|
|
67
241
|
function formatPhase(phase) {
|
|
68
242
|
const colors = { discovery: chalk.blue, build: chalk.green, qa: chalk.yellow, deploy: chalk.magenta, blocked: chalk.red };
|
|
69
243
|
return (colors[phase] || chalk.white)(phase);
|
|
70
244
|
}
|
|
71
245
|
|
|
246
|
+
function formatGovernedPhase(phase) {
|
|
247
|
+
const colors = { planning: chalk.blue, implementation: chalk.green, qa: chalk.yellow, paused: chalk.magenta, failed: chalk.red };
|
|
248
|
+
return (colors[phase] || chalk.white)(phase);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function formatRunStatus(status) {
|
|
252
|
+
if (status === 'blocked') return chalk.red.bold('BLOCKED');
|
|
253
|
+
if (status === 'paused') return chalk.yellow.bold('PAUSED');
|
|
254
|
+
if (status === 'completed') return chalk.green.bold('COMPLETED');
|
|
255
|
+
if (status === 'active') return chalk.cyan('active');
|
|
256
|
+
if (status === 'idle') return chalk.dim('idle');
|
|
257
|
+
return status || chalk.dim('unknown');
|
|
258
|
+
}
|
|
259
|
+
|
|
72
260
|
function timeSince(iso) {
|
|
73
261
|
const ms = Date.now() - new Date(iso).getTime();
|
|
74
262
|
const sec = Math.floor(ms / 1000);
|
|
@@ -78,3 +266,8 @@ function timeSince(iso) {
|
|
|
78
266
|
const hr = Math.floor(min / 60);
|
|
79
267
|
return `${hr}h ${min % 60}m`;
|
|
80
268
|
}
|
|
269
|
+
|
|
270
|
+
function formatUsd(value) {
|
|
271
|
+
if (typeof value !== 'number' || Number.isNaN(value)) return '0.00';
|
|
272
|
+
return value.toFixed(2);
|
|
273
|
+
}
|