agentxchain 2.74.0 → 2.76.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
|
@@ -19,7 +19,7 @@ import { render as renderTimeouts } from './components/timeouts.js';
|
|
|
19
19
|
import { render as renderCoordinatorTimeouts } from './components/coordinator-timeouts.js';
|
|
20
20
|
|
|
21
21
|
const VIEWS = {
|
|
22
|
-
timeline: { fetch: ['state', 'continuity', 'history', 'audit', 'annotations', 'connectors'], render: renderTimeline },
|
|
22
|
+
timeline: { fetch: ['state', 'continuity', 'history', 'audit', 'annotations', 'connectors', 'coordinatorAudit', 'coordinatorAnnotations'], render: renderTimeline },
|
|
23
23
|
ledger: { fetch: ['state', 'ledger', 'coordinatorState', 'coordinatorLedger'], render: renderLedger },
|
|
24
24
|
hooks: { fetch: ['audit', 'annotations', 'coordinatorAudit', 'coordinatorAnnotations'], render: renderHooks },
|
|
25
25
|
blocked: { fetch: ['state', 'audit', 'coordinatorState', 'coordinatorAudit'], render: renderBlocked },
|
|
@@ -114,52 +114,74 @@ function roleBadge(role) {
|
|
|
114
114
|
return `<span class="badge" style="color:${color};border-color:${color}">${esc(role)}</span>`;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
function
|
|
117
|
+
function renderAuditSection(title, auditEntries) {
|
|
118
|
+
if (auditEntries.length === 0) return '';
|
|
119
|
+
let html = `<div class="turn-detail"><span class="detail-label">${esc(title)} (${auditEntries.length}):</span>
|
|
120
|
+
<table class="data-table">
|
|
121
|
+
<thead><tr><th>Phase</th><th>Hook</th><th>Verdict</th></tr></thead>
|
|
122
|
+
<tbody>`;
|
|
123
|
+
for (const entry of auditEntries) {
|
|
124
|
+
const phase = entry.hook_phase || entry.phase || '';
|
|
125
|
+
const hook = entry.hook_name || entry.hook || entry.name || '';
|
|
126
|
+
html += `<tr>
|
|
127
|
+
<td class="mono">${esc(phase)}</td>
|
|
128
|
+
<td>${esc(hook)}</td>
|
|
129
|
+
<td>${esc(entry.verdict || '')}</td>
|
|
130
|
+
</tr>`;
|
|
131
|
+
}
|
|
132
|
+
html += `</tbody></table></div>`;
|
|
133
|
+
return html;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderAnnotationSection(title, annotationEntries) {
|
|
137
|
+
if (annotationEntries.length === 0) return '';
|
|
138
|
+
let html = `<div class="turn-detail"><span class="detail-label">${esc(title)} (${annotationEntries.length}):</span><ul>`;
|
|
139
|
+
for (const ann of annotationEntries) {
|
|
140
|
+
const hookName = ann.hook_name || ann.hook || ann.name || '';
|
|
141
|
+
if (Array.isArray(ann.annotations)) {
|
|
142
|
+
for (const a of ann.annotations) {
|
|
143
|
+
html += `<li>${esc(hookName)}: ${esc(a.key || '')} = ${esc(a.value || '')}</li>`;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
const text = ann.annotation || ann.message || '';
|
|
147
|
+
html += `<li>${esc(hookName)}: ${esc(text)}</li>`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
html += `</ul></div>`;
|
|
151
|
+
return html;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function renderTurnDetailPanel(turnId, annotations, audit, coordinatorAnnotations, coordinatorAudit) {
|
|
118
155
|
const turnAnnotations = Array.isArray(annotations)
|
|
119
156
|
? annotations.filter((a) => a.turn_id === turnId)
|
|
120
157
|
: [];
|
|
121
158
|
const turnAudit = Array.isArray(audit)
|
|
122
159
|
? audit.filter((a) => a.turn_id === turnId)
|
|
123
160
|
: [];
|
|
161
|
+
const turnCoordAnnotations = Array.isArray(coordinatorAnnotations)
|
|
162
|
+
? coordinatorAnnotations.filter((a) => a.turn_id === turnId)
|
|
163
|
+
: [];
|
|
164
|
+
const turnCoordAudit = Array.isArray(coordinatorAudit)
|
|
165
|
+
? coordinatorAudit.filter((a) => a.turn_id === turnId)
|
|
166
|
+
: [];
|
|
167
|
+
|
|
168
|
+
const hasRepo = turnAnnotations.length > 0 || turnAudit.length > 0;
|
|
169
|
+
const hasCoord = turnCoordAnnotations.length > 0 || turnCoordAudit.length > 0;
|
|
124
170
|
|
|
125
|
-
if (
|
|
171
|
+
if (!hasRepo && !hasCoord) {
|
|
126
172
|
return `<div class="turn-detail-panel"><p class="turn-detail">No hook evidence for this turn.</p></div>`;
|
|
127
173
|
}
|
|
128
174
|
|
|
175
|
+
const dual = hasRepo && hasCoord;
|
|
129
176
|
let html = `<div class="turn-detail-panel">`;
|
|
130
177
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<thead><tr><th>Phase</th><th>Hook</th><th>Verdict</th></tr></thead>
|
|
135
|
-
<tbody>`;
|
|
136
|
-
for (const entry of turnAudit) {
|
|
137
|
-
const phase = entry.hook_phase || entry.phase || '';
|
|
138
|
-
const hook = entry.hook_name || entry.hook || entry.name || '';
|
|
139
|
-
html += `<tr>
|
|
140
|
-
<td class="mono">${esc(phase)}</td>
|
|
141
|
-
<td>${esc(hook)}</td>
|
|
142
|
-
<td>${esc(entry.verdict || '')}</td>
|
|
143
|
-
</tr>`;
|
|
144
|
-
}
|
|
145
|
-
html += `</tbody></table></div>`;
|
|
146
|
-
}
|
|
178
|
+
// Repo-local hook evidence
|
|
179
|
+
html += renderAuditSection(dual ? 'Repo Hook Audit Log' : 'Hook Audit Log', turnAudit);
|
|
180
|
+
html += renderAnnotationSection(dual ? 'Repo Hook Annotations' : 'Hook Annotations', turnAnnotations);
|
|
147
181
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const hookName = ann.hook_name || ann.hook || ann.name || '';
|
|
152
|
-
if (Array.isArray(ann.annotations)) {
|
|
153
|
-
for (const a of ann.annotations) {
|
|
154
|
-
html += `<li>${esc(hookName)}: ${esc(a.key || '')} = ${esc(a.value || '')}</li>`;
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
const text = ann.annotation || ann.message || '';
|
|
158
|
-
html += `<li>${esc(hookName)}: ${esc(text)}</li>`;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
html += `</ul></div>`;
|
|
162
|
-
}
|
|
182
|
+
// Coordinator hook evidence
|
|
183
|
+
html += renderAuditSection(dual ? 'Coordinator Hook Audit Log' : 'Hook Audit Log', turnCoordAudit);
|
|
184
|
+
html += renderAnnotationSection(dual ? 'Coordinator Hook Annotations' : 'Hook Annotations', turnCoordAnnotations);
|
|
163
185
|
|
|
164
186
|
html += `</div>`;
|
|
165
187
|
return html;
|
|
@@ -265,7 +287,7 @@ function renderConnectorHealthPanel(connectorsPayload) {
|
|
|
265
287
|
|
|
266
288
|
export { formatDuration, computeElapsed, formatTimestamp };
|
|
267
289
|
|
|
268
|
-
export function render({ state, continuity, history, annotations, audit, connectors }) {
|
|
290
|
+
export function render({ state, continuity, history, annotations, audit, connectors, coordinatorAudit = null, coordinatorAnnotations = null }) {
|
|
269
291
|
if (!state) {
|
|
270
292
|
return `<div class="placeholder"><h2>No Run</h2><p>No governed run found. Start one with <code class="mono">agentxchain init --governed</code></p></div>`;
|
|
271
293
|
}
|
|
@@ -353,7 +375,7 @@ export function render({ state, continuity, history, annotations, audit, connect
|
|
|
353
375
|
html += `<div class="turn-detail"><span class="detail-label">Verification:</span> ${esc(verificationSummary)}</div>`;
|
|
354
376
|
}
|
|
355
377
|
|
|
356
|
-
html += renderTurnDetailPanel(entry.turn_id, annotations, audit);
|
|
378
|
+
html += renderTurnDetailPanel(entry.turn_id, annotations, audit, coordinatorAnnotations, coordinatorAudit);
|
|
357
379
|
|
|
358
380
|
html += `</div>`;
|
|
359
381
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
function usage() {
|
|
8
|
+
console.error('Usage: node scripts/render-github-release-body.mjs --target-version <semver> [--repo <owner/name>]');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function parseArgs(argv) {
|
|
12
|
+
let targetVersion = '';
|
|
13
|
+
let repo = process.env.GITHUB_REPOSITORY || 'shivamtiwari93/agentXchain.dev';
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
16
|
+
const arg = argv[i];
|
|
17
|
+
if (arg === '--target-version') {
|
|
18
|
+
targetVersion = argv[i + 1] || '';
|
|
19
|
+
i += 1;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg === '--repo') {
|
|
23
|
+
repo = argv[i + 1] || '';
|
|
24
|
+
i += 1;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
usage();
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!/^\d+\.\d+\.\d+$/.test(targetVersion)) {
|
|
32
|
+
usage();
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { targetVersion, repo };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function stripFrontmatter(text) {
|
|
40
|
+
return text.replace(/^---\n[\s\S]*?\n---\n*/, '').trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function extractSummaryParagraph(text, version) {
|
|
44
|
+
const heading = `# AgentXchain v${version}`;
|
|
45
|
+
const headingIndex = text.indexOf(heading);
|
|
46
|
+
if (headingIndex === -1) {
|
|
47
|
+
throw new Error(`Release heading missing from governed release page for ${version}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const afterHeading = text.slice(headingIndex + heading.length).trimStart();
|
|
51
|
+
const summaryMatch = afterHeading.match(/^([^\n#][\s\S]*?)\n\s*\n/);
|
|
52
|
+
if (!summaryMatch) {
|
|
53
|
+
throw new Error(`Release summary paragraph missing from governed release page for ${version}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return summaryMatch[1].replace(/\s+/g, ' ').trim();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function extractAggregateEvidenceLine(text) {
|
|
60
|
+
const matches = [...text.matchAll(/^-\s+.*\b(\d+)\s+tests\b.*\b0 failures\b.*$/gm)];
|
|
61
|
+
if (matches.length === 0) {
|
|
62
|
+
throw new Error('Concrete aggregate evidence line missing from governed release page');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const aggregate = matches.reduce((best, match) => {
|
|
66
|
+
const count = Number(match[1]);
|
|
67
|
+
if (!best || count > best.count) {
|
|
68
|
+
return { count, line: match[0] };
|
|
69
|
+
}
|
|
70
|
+
return best;
|
|
71
|
+
}, null);
|
|
72
|
+
|
|
73
|
+
return aggregate.line.replace(/\*\*/g, '').replace(/`/g, '').trim();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getPreviousVersionTag(repoRoot, version) {
|
|
77
|
+
const currentTag = `v${version}`;
|
|
78
|
+
const output = execFileSync(
|
|
79
|
+
'git',
|
|
80
|
+
['tag', '--list', 'v*.*.*', '--sort=-v:refname'],
|
|
81
|
+
{ cwd: repoRoot, encoding: 'utf8' },
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const tags = output.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
85
|
+
const currentIndex = tags.indexOf(currentTag);
|
|
86
|
+
if (currentIndex === -1 || currentIndex === tags.length - 1) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return tags[currentIndex + 1];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function renderBody({ version, repo, summary, evidence, previousTag }) {
|
|
93
|
+
const docsUrl = `https://agentxchain.dev/docs/releases/v${version.replace(/\./g, '-')}`;
|
|
94
|
+
const npmUrl = `https://www.npmjs.com/package/agentxchain/v/${version}`;
|
|
95
|
+
const lines = [
|
|
96
|
+
`Public release notes: ${docsUrl}`,
|
|
97
|
+
`npm package: ${npmUrl}`,
|
|
98
|
+
'',
|
|
99
|
+
summary,
|
|
100
|
+
'',
|
|
101
|
+
'## Evidence',
|
|
102
|
+
evidence,
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
if (previousTag) {
|
|
106
|
+
lines.push('', `Full Changelog: https://github.com/${repo}/compare/${previousTag}...v${version}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `${lines.join('\n')}\n`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function main() {
|
|
113
|
+
const { targetVersion, repo } = parseArgs(process.argv.slice(2));
|
|
114
|
+
const repoRoot = resolve(import.meta.dirname, '..', '..');
|
|
115
|
+
const releaseDocPath = resolve(
|
|
116
|
+
repoRoot,
|
|
117
|
+
'website-v2',
|
|
118
|
+
'docs',
|
|
119
|
+
'releases',
|
|
120
|
+
`v${targetVersion.replace(/\./g, '-')}.mdx`,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!existsSync(releaseDocPath)) {
|
|
124
|
+
throw new Error(`Governed release page missing: ${releaseDocPath}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const rawDoc = readFileSync(releaseDocPath, 'utf8');
|
|
128
|
+
const doc = stripFrontmatter(rawDoc);
|
|
129
|
+
const summary = extractSummaryParagraph(doc, targetVersion);
|
|
130
|
+
const evidence = extractAggregateEvidenceLine(doc);
|
|
131
|
+
const previousTag = getPreviousVersionTag(repoRoot, targetVersion);
|
|
132
|
+
process.stdout.write(
|
|
133
|
+
renderBody({
|
|
134
|
+
version: targetVersion,
|
|
135
|
+
repo,
|
|
136
|
+
summary,
|
|
137
|
+
evidence,
|
|
138
|
+
previousTag,
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
main();
|