agentxchain 0.8.7 → 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.
Files changed (94) hide show
  1. package/README.md +123 -154
  2. package/bin/agentxchain.js +240 -8
  3. package/dashboard/app.js +305 -0
  4. package/dashboard/components/blocked.js +145 -0
  5. package/dashboard/components/cross-repo.js +126 -0
  6. package/dashboard/components/gate.js +311 -0
  7. package/dashboard/components/hooks.js +177 -0
  8. package/dashboard/components/initiative.js +147 -0
  9. package/dashboard/components/ledger.js +165 -0
  10. package/dashboard/components/timeline.js +222 -0
  11. package/dashboard/index.html +352 -0
  12. package/package.json +16 -7
  13. package/scripts/agentxchain-autonudge.applescript +32 -5
  14. package/scripts/live-api-proxy-preflight-smoke.sh +531 -0
  15. package/scripts/publish-from-tag.sh +88 -0
  16. package/scripts/release-postflight.sh +231 -0
  17. package/scripts/release-preflight.sh +167 -0
  18. package/scripts/run-autonudge.sh +1 -1
  19. package/src/adapters/claude-code.js +7 -14
  20. package/src/adapters/cursor-local.js +17 -16
  21. package/src/commands/accept-turn.js +160 -0
  22. package/src/commands/approve-completion.js +80 -0
  23. package/src/commands/approve-transition.js +85 -0
  24. package/src/commands/branch.js +2 -2
  25. package/src/commands/claim.js +84 -9
  26. package/src/commands/config.js +16 -0
  27. package/src/commands/dashboard.js +70 -0
  28. package/src/commands/doctor.js +9 -1
  29. package/src/commands/init.js +540 -5
  30. package/src/commands/migrate.js +348 -0
  31. package/src/commands/multi.js +549 -0
  32. package/src/commands/plugin.js +157 -0
  33. package/src/commands/reject-turn.js +204 -0
  34. package/src/commands/resume.js +389 -0
  35. package/src/commands/status.js +196 -3
  36. package/src/commands/step.js +947 -0
  37. package/src/commands/stop.js +65 -33
  38. package/src/commands/template-list.js +33 -0
  39. package/src/commands/template-set.js +279 -0
  40. package/src/commands/update.js +24 -3
  41. package/src/commands/validate.js +20 -11
  42. package/src/commands/verify.js +71 -0
  43. package/src/commands/watch.js +112 -25
  44. package/src/lib/adapters/api-proxy-adapter.js +1076 -0
  45. package/src/lib/adapters/local-cli-adapter.js +337 -0
  46. package/src/lib/adapters/manual-adapter.js +169 -0
  47. package/src/lib/blocked-state.js +94 -0
  48. package/src/lib/config.js +143 -12
  49. package/src/lib/context-compressor.js +121 -0
  50. package/src/lib/context-section-parser.js +220 -0
  51. package/src/lib/coordinator-acceptance.js +428 -0
  52. package/src/lib/coordinator-config.js +461 -0
  53. package/src/lib/coordinator-dispatch.js +276 -0
  54. package/src/lib/coordinator-gates.js +487 -0
  55. package/src/lib/coordinator-hooks.js +239 -0
  56. package/src/lib/coordinator-recovery.js +523 -0
  57. package/src/lib/coordinator-state.js +365 -0
  58. package/src/lib/cross-repo-context.js +247 -0
  59. package/src/lib/dashboard/bridge-server.js +284 -0
  60. package/src/lib/dashboard/file-watcher.js +93 -0
  61. package/src/lib/dashboard/state-reader.js +96 -0
  62. package/src/lib/dispatch-bundle.js +568 -0
  63. package/src/lib/dispatch-manifest.js +252 -0
  64. package/src/lib/filter-agents.js +12 -0
  65. package/src/lib/gate-evaluator.js +285 -0
  66. package/src/lib/generate-vscode.js +158 -68
  67. package/src/lib/governed-state.js +2139 -0
  68. package/src/lib/governed-templates.js +145 -0
  69. package/src/lib/hook-runner.js +788 -0
  70. package/src/lib/next-owner.js +61 -6
  71. package/src/lib/normalized-config.js +539 -0
  72. package/src/lib/notify.js +14 -12
  73. package/src/lib/plugin-config-schema.js +192 -0
  74. package/src/lib/plugins.js +692 -0
  75. package/src/lib/prompt-core.js +108 -0
  76. package/src/lib/protocol-conformance.js +291 -0
  77. package/src/lib/reference-conformance-adapter.js +717 -0
  78. package/src/lib/repo-observer.js +597 -0
  79. package/src/lib/repo.js +0 -31
  80. package/src/lib/safe-write.js +44 -0
  81. package/src/lib/schema.js +189 -0
  82. package/src/lib/schemas/turn-result.schema.json +205 -0
  83. package/src/lib/seed-prompt-polling.js +15 -73
  84. package/src/lib/seed-prompt.js +17 -63
  85. package/src/lib/token-budget.js +206 -0
  86. package/src/lib/token-counter.js +27 -0
  87. package/src/lib/turn-paths.js +67 -0
  88. package/src/lib/turn-result-validator.js +496 -0
  89. package/src/lib/validation.js +167 -19
  90. package/src/lib/verify-command.js +72 -0
  91. package/src/templates/governed/api-service.json +31 -0
  92. package/src/templates/governed/cli-tool.json +30 -0
  93. package/src/templates/governed/generic.json +10 -0
  94. package/src/templates/governed/web-app.json +30 -0
@@ -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 result = loadConfig();
6
- if (!result) {
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
+ }