agentxchain 2.71.0 → 2.72.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/dashboard/app.js CHANGED
@@ -20,7 +20,7 @@ import { render as renderCoordinatorTimeouts } from './components/coordinator-ti
20
20
 
21
21
  const VIEWS = {
22
22
  timeline: { fetch: ['state', 'continuity', 'history', 'audit', 'annotations', 'connectors'], render: renderTimeline },
23
- ledger: { fetch: ['ledger'], render: renderLedger },
23
+ ledger: { fetch: ['state', 'ledger', 'coordinatorState', 'coordinatorLedger'], render: renderLedger },
24
24
  hooks: { fetch: ['audit', 'annotations'], render: renderHooks },
25
25
  blocked: { fetch: ['state', 'audit', 'coordinatorState', 'coordinatorAudit'], render: renderBlocked },
26
26
  gate: { fetch: ['state', 'history', 'coordinatorState', 'coordinatorHistory', 'coordinatorBarriers'], render: renderGate },
@@ -38,6 +38,7 @@ const API_MAP = {
38
38
  continuity: '/api/continuity',
39
39
  history: '/api/history',
40
40
  ledger: '/api/ledger',
41
+ coordinatorLedger: '/api/coordinator/ledger',
41
42
  audit: '/api/hooks/audit',
42
43
  annotations: '/api/hooks/annotations',
43
44
  coordinatorState: '/api/coordinator/state',
@@ -79,12 +79,7 @@ function hasObjections(entry) {
79
79
  return Array.isArray(entry.objections) && entry.objections.length > 0;
80
80
  }
81
81
 
82
- export function render({ ledger, filter = {} }) {
83
- if (!ledger || ledger.length === 0) {
84
- return `<div class="placeholder"><h2>Decision Ledger</h2><p>No decisions recorded yet.</p></div>`;
85
- }
86
-
87
- const filtered = filterEntries(ledger, filter);
82
+ function renderFilterBar(ledger, filter) {
88
83
  const selectedAgent = filter.agent || 'all';
89
84
  const selectedPhase = filter.phase || 'all';
90
85
  const dateFrom = filter.dateFrom || '';
@@ -93,56 +88,57 @@ export function render({ ledger, filter = {} }) {
93
88
  const agents = collectAgents(ledger);
94
89
  const phases = collectPhases(ledger);
95
90
 
96
- let html = `<div class="ledger-view">
97
- <div class="section"><h3>Decision Ledger</h3>
98
- <p class="section-subtitle">${filtered.length} of ${ledger.length} decision${ledger.length !== 1 ? 's' : ''} shown</p>
99
- <div class="filter-bar">
100
- <label class="filter-control">
101
- <span>Agent</span>
102
- <select data-view-control="ledger-agent">
103
- <option value="all"${selectedAgent === 'all' ? ' selected' : ''}>All roles</option>
104
- ${agents.map((agent) => `<option value="${esc(agent)}"${selectedAgent === agent ? ' selected' : ''}>${esc(agent)}</option>`).join('')}
105
- </select>
106
- </label>
107
- <label class="filter-control">
108
- <span>Phase</span>
109
- <select data-view-control="ledger-phase">
110
- <option value="all"${selectedPhase === 'all' ? ' selected' : ''}>All phases</option>
111
- ${phases.map((p) => `<option value="${esc(p)}"${selectedPhase === p ? ' selected' : ''}>${esc(p)}</option>`).join('')}
112
- </select>
113
- </label>
114
- <label class="filter-control">
115
- <span>Search</span>
116
- <input
117
- type="search"
118
- data-view-control="ledger-query"
119
- value="${esc(query)}"
120
- placeholder="Filter by role or decision"
121
- autocomplete="off"
122
- >
123
- </label>
124
- <label class="filter-control">
125
- <span>From</span>
126
- <input
127
- type="date"
128
- data-view-control="ledger-date-from"
129
- value="${esc(dateFrom)}"
130
- autocomplete="off"
131
- >
132
- </label>
133
- <label class="filter-control">
134
- <span>To</span>
135
- <input
136
- type="date"
137
- data-view-control="ledger-date-to"
138
- value="${esc(dateTo)}"
139
- autocomplete="off"
140
- >
141
- </label>
142
- </div>
143
- <table class="data-table">
144
- <thead><tr><th>Turn</th><th>Agent</th><th>Decision</th><th>Timestamp</th></tr></thead>
145
- <tbody>`;
91
+ return `<div class="filter-bar">
92
+ <label class="filter-control">
93
+ <span>Agent</span>
94
+ <select data-view-control="ledger-agent">
95
+ <option value="all"${selectedAgent === 'all' ? ' selected' : ''}>All roles</option>
96
+ ${agents.map((agent) => `<option value="${esc(agent)}"${selectedAgent === agent ? ' selected' : ''}>${esc(agent)}</option>`).join('')}
97
+ </select>
98
+ </label>
99
+ <label class="filter-control">
100
+ <span>Phase</span>
101
+ <select data-view-control="ledger-phase">
102
+ <option value="all"${selectedPhase === 'all' ? ' selected' : ''}>All phases</option>
103
+ ${phases.map((p) => `<option value="${esc(p)}"${selectedPhase === p ? ' selected' : ''}>${esc(p)}</option>`).join('')}
104
+ </select>
105
+ </label>
106
+ <label class="filter-control">
107
+ <span>Search</span>
108
+ <input
109
+ type="search"
110
+ data-view-control="ledger-query"
111
+ value="${esc(query)}"
112
+ placeholder="Filter by role or decision"
113
+ autocomplete="off"
114
+ >
115
+ </label>
116
+ <label class="filter-control">
117
+ <span>From</span>
118
+ <input
119
+ type="date"
120
+ data-view-control="ledger-date-from"
121
+ value="${esc(dateFrom)}"
122
+ autocomplete="off"
123
+ >
124
+ </label>
125
+ <label class="filter-control">
126
+ <span>To</span>
127
+ <input
128
+ type="date"
129
+ data-view-control="ledger-date-to"
130
+ value="${esc(dateTo)}"
131
+ autocomplete="off"
132
+ >
133
+ </label>
134
+ </div>`;
135
+ }
136
+
137
+ function renderLedgerTable(entries, filter) {
138
+ const filtered = filterEntries(entries, filter);
139
+ let html = `<table class="data-table">
140
+ <thead><tr><th>Turn</th><th>Agent</th><th>Decision</th><th>Timestamp</th></tr></thead>
141
+ <tbody>`;
146
142
 
147
143
  if (filtered.length === 0) {
148
144
  html += `<tr><td colspan="4">No decisions match the current filters.</td></tr>`;
@@ -160,6 +156,65 @@ export function render({ ledger, filter = {} }) {
160
156
  }
161
157
  }
162
158
 
163
- html += `</tbody></table></div></div>`;
159
+ html += `</tbody></table>`;
160
+ return { html, filteredCount: filtered.length };
161
+ }
162
+
163
+ function buildSections({ ledger, coordinatorLedger, state, coordinatorState }) {
164
+ const sections = [];
165
+ const hasRepoContext = Boolean(state) || (Array.isArray(ledger) && ledger.length > 0);
166
+ const hasCoordinatorContext = Boolean(coordinatorState) || (Array.isArray(coordinatorLedger) && coordinatorLedger.length > 0);
167
+
168
+ if (hasRepoContext) {
169
+ sections.push({
170
+ title: hasCoordinatorContext ? 'Repo Decision Ledger' : 'Decision Ledger',
171
+ entries: Array.isArray(ledger) ? ledger : [],
172
+ emptyMessage: 'No repo-local decisions recorded yet.',
173
+ });
174
+ }
175
+
176
+ if (hasCoordinatorContext) {
177
+ sections.push({
178
+ title: hasRepoContext ? 'Coordinator Decision Ledger' : 'Coordinator Decision Ledger',
179
+ entries: Array.isArray(coordinatorLedger) ? coordinatorLedger : [],
180
+ emptyMessage: 'No coordinator decisions recorded yet.',
181
+ });
182
+ }
183
+
184
+ return sections;
185
+ }
186
+
187
+ export function render({
188
+ ledger,
189
+ coordinatorLedger = null,
190
+ state = null,
191
+ coordinatorState = null,
192
+ filter = {},
193
+ }) {
194
+ const sections = buildSections({ ledger, coordinatorLedger, state, coordinatorState });
195
+ if (sections.length === 0) {
196
+ return `<div class="placeholder"><h2>Decision Ledger</h2><p>No decisions recorded yet.</p></div>`;
197
+ }
198
+
199
+ const combinedLedger = sections.flatMap((section) => section.entries);
200
+ let html = `<div class="ledger-view">
201
+ <div class="section"><h3>Decisions</h3>
202
+ <p class="section-subtitle">${sections.length === 1 ? 'Decision ledger surface' : 'Repo-local and coordinator decision ledgers'}</p>
203
+ ${renderFilterBar(combinedLedger, filter)}
204
+ </div>`;
205
+
206
+ for (const section of sections) {
207
+ const { html: tableHtml, filteredCount } = renderLedgerTable(section.entries, filter);
208
+ html += `<div class="section"><h3>${section.title}</h3>
209
+ <p class="section-subtitle">${filteredCount} of ${section.entries.length} decision${section.entries.length !== 1 ? 's' : ''} shown</p>`;
210
+ if (section.entries.length === 0) {
211
+ html += `<div class="placeholder compact"><p>${section.emptyMessage}</p></div>`;
212
+ } else {
213
+ html += tableHtml;
214
+ }
215
+ html += `</div>`;
216
+ }
217
+
218
+ html += `</div>`;
164
219
  return html;
165
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxchain",
3
- "version": "2.71.0",
3
+ "version": "2.72.0",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {