@agent-inspect/viewer 6.3.0 → 6.4.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/dist/index.cjs +25 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +25 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -21,7 +21,7 @@ interface ViewerServerInfo {
|
|
|
21
21
|
declare function createViewerServer(options?: ViewerServerOptions): Server;
|
|
22
22
|
declare function startViewerServer(options?: ViewerServerOptions): Promise<ViewerServerInfo>;
|
|
23
23
|
|
|
24
|
-
declare const viewerIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Viewer</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n pre { background: #f4f4f5; padding: 1rem; overflow: auto; max-height: 50vh; }\n a { color: #0b57d0; }\n .muted { color: #666; }\n table { border-collapse: collapse; width: 100%; margin: 1rem 0; }\n th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; vertical-align: top; }\n th { background: #f6f6f6; }\n .fail { color: #b42318; font-weight: 600; }\n .pass { color: #027a48; font-weight: 600; }\n section { margin: 1.5rem 0; }\n </style>\n</head>\n<body>\n <h1>AgentInspect local viewer</h1>\n <p class=\"muted\">Read-only. JSONL on disk remains canonical.</p>\n <p id=\"nav\"></p>\n <div id=\"content\"><pre id=\"out\">Loading\u2026</pre></div>\n <script>\n const params = new URLSearchParams(location.search);\n const mode = params.get(\"mode\") || \"traces\";\n\n function renderSuite(data) {\n const rows = data.cases.map((c) =>\n '<tr><td>' + c.id + '</td><td class=\"' + c.status + '\">' + c.status +\n '</td><td>' + (c.message || '') + '</td><td>' + c.toolPath.join(' \u2192 ') +\n '</td><td>' + c.observations.map((o) => o.name + ':' + o.status).join(', ') + '</td></tr>'\n ).join('');\n const failed = data.cases.filter((c) => c.status !== 'pass');\n const detail = failed.map((c) => {\n let html = '<h3>Case ' + c.id + '</h3><ul>';\n if (c.failureDiff) html += '<li>Diff errors: ' + c.failureDiff.summary.errors + '</li>';\n if (c.timeline) html += '<li>Timeline steps: ' + c.timeline.entries.length + '</li>';\n html += '<li>Diagnostics: ' + c.diagnostics.map((d) => d.message).join('; ') + '</li></ul>';\n return html;\n }).join('');\n return '<section><h2>Suite: ' + data.suiteName + ' (' + data.status + ')</h2>' +\n '<p>Passed ' + data.summary.passed + ', failed ' + data.summary.failed + '</p>' +\n '<table><thead><tr><th>Case</th><th>Status</th><th>Message</th><th>Tool path</th><th>Observations</th></tr></thead><tbody>' +\n rows + '</tbody></table>' +\n '<section><h2>Failure detail</h2>' + (detail || '<p class=\"pass\">No failures</p>') + '</section>' +\n '<section><h2>CI artifacts</h2><p>' + (data.ciArtifactsDir || 'n/a') + '</p></section>' +\n '<section><h2>Bundle export</h2><p>' + data.bundleExportHint + '</p></section>';\n }\n\n async function load() {\n const nav = document.getElementById(\"nav\");\n const out = document.getElementById(\"out\");\n const content = document.getElementById(\"content\");\n if (mode === \"suite\") {\n nav.innerHTML = '<a href=\"/api/suite\">/api/suite</a>';\n const data = await fetch(\"/api/suite\").then((r) => r.json());\n content.innerHTML = renderSuite(data);\n return;\n }\n if (mode === \"workspace\") {\n nav.innerHTML = '<a href=\"/api/workspace\">/api/workspace</a>';\n const data = await fetch(\"/api/workspace\").then((r) => r.json());\n content.innerHTML = '<section><h2>Workspace: ' + (data.project || 'workspace') + '</h2>' +\n '<p>Runs: ' + data.runs.length + '</p><pre>' + JSON.stringify(data, null, 2) + '</pre></section>';\n return;\n }\n nav.innerHTML = '<a href=\"/api/traces\">/api/traces</a> \u00B7 <a href=\"/api/sessions\">/api/sessions</a>';\n const data = await fetch(\"/api/traces\").then((r) => r.json());\n out.textContent = JSON.stringify(data, null, 2);\n }\n load().catch((err) => {\n document.getElementById(\"out\").textContent = String(err);\n });\n </script>\n</body>\n</html>\n";
|
|
24
|
+
declare const viewerIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Viewer</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n pre { background: #f4f4f5; padding: 1rem; overflow: auto; max-height: 50vh; }\n a { color: #0b57d0; }\n .muted { color: #666; }\n table { border-collapse: collapse; width: 100%; margin: 1rem 0; }\n th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; vertical-align: top; }\n th { background: #f6f6f6; }\n .fail { color: #b42318; font-weight: 600; }\n .pass { color: #027a48; font-weight: 600; }\n section { margin: 1.5rem 0; }\n </style>\n</head>\n<body>\n <h1>AgentInspect local viewer</h1>\n <p class=\"muted\">Read-only. JSONL on disk remains canonical.</p>\n <p id=\"nav\"></p>\n <div id=\"content\"><pre id=\"out\">Loading\u2026</pre></div>\n <script>\n const params = new URLSearchParams(location.search);\n const mode = params.get(\"mode\") || \"traces\";\n\n function escapeHtml(value) {\n return String(value ?? \"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n }\n\n function renderSuite(data) {\n const rows = data.cases.map((c) =>\n '<tr><td>' + escapeHtml(c.id) + '</td><td class=\"' + escapeHtml(c.status) + '\">' + escapeHtml(c.status) +\n '</td><td>' + escapeHtml(c.message || '') + '</td><td>' + escapeHtml(c.toolPath.join(' \u2192 ')) +\n '</td><td>' + escapeHtml(c.observations.map((o) => o.name + ':' + o.status).join(', ')) + '</td></tr>'\n ).join('');\n const failed = data.cases.filter((c) => c.status !== 'pass');\n const detail = failed.map((c) => {\n let html = '<h3>Case ' + escapeHtml(c.id) + '</h3><ul>';\n if (c.failureDiff) html += '<li>Diff errors: ' + escapeHtml(c.failureDiff.summary.errors) + '</li>';\n if (c.timeline) html += '<li>Timeline steps: ' + escapeHtml(c.timeline.entries.length) + '</li>';\n html += '<li>Diagnostics: ' + escapeHtml(c.diagnostics.map((d) => d.message).join('; ')) + '</li></ul>';\n return html;\n }).join('');\n return '<section><h2>Suite: ' + escapeHtml(data.suiteName) + ' (' + escapeHtml(data.status) + ')</h2>' +\n '<p>Passed ' + escapeHtml(data.summary.passed) + ', failed ' + escapeHtml(data.summary.failed) + '</p>' +\n '<table><thead><tr><th>Case</th><th>Status</th><th>Message</th><th>Tool path</th><th>Observations</th></tr></thead><tbody>' +\n rows + '</tbody></table>' +\n '<section><h2>Failure detail</h2>' + (detail || '<p class=\"pass\">No failures</p>') + '</section>' +\n '<section><h2>CI artifacts</h2><p>' + escapeHtml(data.ciArtifactsDir || 'n/a') + '</p></section>' +\n '<section><h2>Bundle export</h2><p>' + escapeHtml(data.bundleExportHint) + '</p></section>';\n }\n\n async function load() {\n const nav = document.getElementById(\"nav\");\n const out = document.getElementById(\"out\");\n const content = document.getElementById(\"content\");\n if (mode === \"suite\") {\n nav.innerHTML = '<a href=\"/api/suite\">/api/suite</a>';\n const data = await fetch(\"/api/suite\").then((r) => r.json());\n content.innerHTML = renderSuite(data);\n return;\n }\n if (mode === \"workspace\") {\n nav.innerHTML = '<a href=\"/api/workspace\">/api/workspace</a>';\n const data = await fetch(\"/api/workspace\").then((r) => r.json());\n content.innerHTML = '<section><h2>Workspace: ' + escapeHtml(data.project || 'workspace') + '</h2>' +\n '<p>Runs: ' + escapeHtml(data.runs.length) + '</p><pre>' + escapeHtml(JSON.stringify(data, null, 2)) + '</pre></section>';\n return;\n }\n nav.innerHTML = '<a href=\"/api/traces\">/api/traces</a> \u00B7 <a href=\"/api/sessions\">/api/sessions</a>';\n const data = await fetch(\"/api/traces\").then((r) => r.json());\n out.textContent = JSON.stringify(data, null, 2);\n }\n load().catch((err) => {\n document.getElementById(\"out\").textContent = String(err);\n });\n </script>\n</body>\n</html>\n";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Discriminator for what kind of work a {@link Step} represents.
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ interface ViewerServerInfo {
|
|
|
21
21
|
declare function createViewerServer(options?: ViewerServerOptions): Server;
|
|
22
22
|
declare function startViewerServer(options?: ViewerServerOptions): Promise<ViewerServerInfo>;
|
|
23
23
|
|
|
24
|
-
declare const viewerIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Viewer</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n pre { background: #f4f4f5; padding: 1rem; overflow: auto; max-height: 50vh; }\n a { color: #0b57d0; }\n .muted { color: #666; }\n table { border-collapse: collapse; width: 100%; margin: 1rem 0; }\n th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; vertical-align: top; }\n th { background: #f6f6f6; }\n .fail { color: #b42318; font-weight: 600; }\n .pass { color: #027a48; font-weight: 600; }\n section { margin: 1.5rem 0; }\n </style>\n</head>\n<body>\n <h1>AgentInspect local viewer</h1>\n <p class=\"muted\">Read-only. JSONL on disk remains canonical.</p>\n <p id=\"nav\"></p>\n <div id=\"content\"><pre id=\"out\">Loading\u2026</pre></div>\n <script>\n const params = new URLSearchParams(location.search);\n const mode = params.get(\"mode\") || \"traces\";\n\n function renderSuite(data) {\n const rows = data.cases.map((c) =>\n '<tr><td>' + c.id + '</td><td class=\"' + c.status + '\">' + c.status +\n '</td><td>' + (c.message || '') + '</td><td>' + c.toolPath.join(' \u2192 ') +\n '</td><td>' + c.observations.map((o) => o.name + ':' + o.status).join(', ') + '</td></tr>'\n ).join('');\n const failed = data.cases.filter((c) => c.status !== 'pass');\n const detail = failed.map((c) => {\n let html = '<h3>Case ' + c.id + '</h3><ul>';\n if (c.failureDiff) html += '<li>Diff errors: ' + c.failureDiff.summary.errors + '</li>';\n if (c.timeline) html += '<li>Timeline steps: ' + c.timeline.entries.length + '</li>';\n html += '<li>Diagnostics: ' + c.diagnostics.map((d) => d.message).join('; ') + '</li></ul>';\n return html;\n }).join('');\n return '<section><h2>Suite: ' + data.suiteName + ' (' + data.status + ')</h2>' +\n '<p>Passed ' + data.summary.passed + ', failed ' + data.summary.failed + '</p>' +\n '<table><thead><tr><th>Case</th><th>Status</th><th>Message</th><th>Tool path</th><th>Observations</th></tr></thead><tbody>' +\n rows + '</tbody></table>' +\n '<section><h2>Failure detail</h2>' + (detail || '<p class=\"pass\">No failures</p>') + '</section>' +\n '<section><h2>CI artifacts</h2><p>' + (data.ciArtifactsDir || 'n/a') + '</p></section>' +\n '<section><h2>Bundle export</h2><p>' + data.bundleExportHint + '</p></section>';\n }\n\n async function load() {\n const nav = document.getElementById(\"nav\");\n const out = document.getElementById(\"out\");\n const content = document.getElementById(\"content\");\n if (mode === \"suite\") {\n nav.innerHTML = '<a href=\"/api/suite\">/api/suite</a>';\n const data = await fetch(\"/api/suite\").then((r) => r.json());\n content.innerHTML = renderSuite(data);\n return;\n }\n if (mode === \"workspace\") {\n nav.innerHTML = '<a href=\"/api/workspace\">/api/workspace</a>';\n const data = await fetch(\"/api/workspace\").then((r) => r.json());\n content.innerHTML = '<section><h2>Workspace: ' + (data.project || 'workspace') + '</h2>' +\n '<p>Runs: ' + data.runs.length + '</p><pre>' + JSON.stringify(data, null, 2) + '</pre></section>';\n return;\n }\n nav.innerHTML = '<a href=\"/api/traces\">/api/traces</a> \u00B7 <a href=\"/api/sessions\">/api/sessions</a>';\n const data = await fetch(\"/api/traces\").then((r) => r.json());\n out.textContent = JSON.stringify(data, null, 2);\n }\n load().catch((err) => {\n document.getElementById(\"out\").textContent = String(err);\n });\n </script>\n</body>\n</html>\n";
|
|
24
|
+
declare const viewerIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Viewer</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n pre { background: #f4f4f5; padding: 1rem; overflow: auto; max-height: 50vh; }\n a { color: #0b57d0; }\n .muted { color: #666; }\n table { border-collapse: collapse; width: 100%; margin: 1rem 0; }\n th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; vertical-align: top; }\n th { background: #f6f6f6; }\n .fail { color: #b42318; font-weight: 600; }\n .pass { color: #027a48; font-weight: 600; }\n section { margin: 1.5rem 0; }\n </style>\n</head>\n<body>\n <h1>AgentInspect local viewer</h1>\n <p class=\"muted\">Read-only. JSONL on disk remains canonical.</p>\n <p id=\"nav\"></p>\n <div id=\"content\"><pre id=\"out\">Loading\u2026</pre></div>\n <script>\n const params = new URLSearchParams(location.search);\n const mode = params.get(\"mode\") || \"traces\";\n\n function escapeHtml(value) {\n return String(value ?? \"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n }\n\n function renderSuite(data) {\n const rows = data.cases.map((c) =>\n '<tr><td>' + escapeHtml(c.id) + '</td><td class=\"' + escapeHtml(c.status) + '\">' + escapeHtml(c.status) +\n '</td><td>' + escapeHtml(c.message || '') + '</td><td>' + escapeHtml(c.toolPath.join(' \u2192 ')) +\n '</td><td>' + escapeHtml(c.observations.map((o) => o.name + ':' + o.status).join(', ')) + '</td></tr>'\n ).join('');\n const failed = data.cases.filter((c) => c.status !== 'pass');\n const detail = failed.map((c) => {\n let html = '<h3>Case ' + escapeHtml(c.id) + '</h3><ul>';\n if (c.failureDiff) html += '<li>Diff errors: ' + escapeHtml(c.failureDiff.summary.errors) + '</li>';\n if (c.timeline) html += '<li>Timeline steps: ' + escapeHtml(c.timeline.entries.length) + '</li>';\n html += '<li>Diagnostics: ' + escapeHtml(c.diagnostics.map((d) => d.message).join('; ')) + '</li></ul>';\n return html;\n }).join('');\n return '<section><h2>Suite: ' + escapeHtml(data.suiteName) + ' (' + escapeHtml(data.status) + ')</h2>' +\n '<p>Passed ' + escapeHtml(data.summary.passed) + ', failed ' + escapeHtml(data.summary.failed) + '</p>' +\n '<table><thead><tr><th>Case</th><th>Status</th><th>Message</th><th>Tool path</th><th>Observations</th></tr></thead><tbody>' +\n rows + '</tbody></table>' +\n '<section><h2>Failure detail</h2>' + (detail || '<p class=\"pass\">No failures</p>') + '</section>' +\n '<section><h2>CI artifacts</h2><p>' + escapeHtml(data.ciArtifactsDir || 'n/a') + '</p></section>' +\n '<section><h2>Bundle export</h2><p>' + escapeHtml(data.bundleExportHint) + '</p></section>';\n }\n\n async function load() {\n const nav = document.getElementById(\"nav\");\n const out = document.getElementById(\"out\");\n const content = document.getElementById(\"content\");\n if (mode === \"suite\") {\n nav.innerHTML = '<a href=\"/api/suite\">/api/suite</a>';\n const data = await fetch(\"/api/suite\").then((r) => r.json());\n content.innerHTML = renderSuite(data);\n return;\n }\n if (mode === \"workspace\") {\n nav.innerHTML = '<a href=\"/api/workspace\">/api/workspace</a>';\n const data = await fetch(\"/api/workspace\").then((r) => r.json());\n content.innerHTML = '<section><h2>Workspace: ' + escapeHtml(data.project || 'workspace') + '</h2>' +\n '<p>Runs: ' + escapeHtml(data.runs.length) + '</p><pre>' + escapeHtml(JSON.stringify(data, null, 2)) + '</pre></section>';\n return;\n }\n nav.innerHTML = '<a href=\"/api/traces\">/api/traces</a> \u00B7 <a href=\"/api/sessions\">/api/sessions</a>';\n const data = await fetch(\"/api/traces\").then((r) => r.json());\n out.textContent = JSON.stringify(data, null, 2);\n }\n load().catch((err) => {\n document.getElementById(\"out\").textContent = String(err);\n });\n </script>\n</body>\n</html>\n";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Discriminator for what kind of work a {@link Step} represents.
|
package/dist/index.mjs
CHANGED
|
@@ -4591,8 +4591,9 @@ async function runSuite(options = {}) {
|
|
|
4591
4591
|
skipped: cases.filter((item) => item.status === "skipped").length
|
|
4592
4592
|
};
|
|
4593
4593
|
const finishedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
4594
|
-
const
|
|
4595
|
-
const
|
|
4594
|
+
const allSkipped = cases.length > 0 && summary.skipped === cases.length;
|
|
4595
|
+
const ok = summary.failed === 0 && summary.errors === 0 && !allSkipped;
|
|
4596
|
+
const status = summary.errors > 0 ? "error" : allSkipped ? "fail" : summary.failed > 0 || !ok ? "fail" : "pass";
|
|
4596
4597
|
return {
|
|
4597
4598
|
ok,
|
|
4598
4599
|
status,
|
|
@@ -4652,27 +4653,36 @@ var viewerIndexHtml = `<!DOCTYPE html>
|
|
|
4652
4653
|
const params = new URLSearchParams(location.search);
|
|
4653
4654
|
const mode = params.get("mode") || "traces";
|
|
4654
4655
|
|
|
4656
|
+
function escapeHtml(value) {
|
|
4657
|
+
return String(value ?? "")
|
|
4658
|
+
.replaceAll("&", "&")
|
|
4659
|
+
.replaceAll("<", "<")
|
|
4660
|
+
.replaceAll(">", ">")
|
|
4661
|
+
.replaceAll('"', """)
|
|
4662
|
+
.replaceAll("'", "'");
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4655
4665
|
function renderSuite(data) {
|
|
4656
4666
|
const rows = data.cases.map((c) =>
|
|
4657
|
-
'<tr><td>' + c.id + '</td><td class="' + c.status + '">' + c.status +
|
|
4658
|
-
'</td><td>' + (c.message || '') + '</td><td>' + c.toolPath.join(' \u2192 ') +
|
|
4659
|
-
'</td><td>' + c.observations.map((o) => o.name + ':' + o.status).join(', ') + '</td></tr>'
|
|
4667
|
+
'<tr><td>' + escapeHtml(c.id) + '</td><td class="' + escapeHtml(c.status) + '">' + escapeHtml(c.status) +
|
|
4668
|
+
'</td><td>' + escapeHtml(c.message || '') + '</td><td>' + escapeHtml(c.toolPath.join(' \u2192 ')) +
|
|
4669
|
+
'</td><td>' + escapeHtml(c.observations.map((o) => o.name + ':' + o.status).join(', ')) + '</td></tr>'
|
|
4660
4670
|
).join('');
|
|
4661
4671
|
const failed = data.cases.filter((c) => c.status !== 'pass');
|
|
4662
4672
|
const detail = failed.map((c) => {
|
|
4663
|
-
let html = '<h3>Case ' + c.id + '</h3><ul>';
|
|
4664
|
-
if (c.failureDiff) html += '<li>Diff errors: ' + c.failureDiff.summary.errors + '</li>';
|
|
4665
|
-
if (c.timeline) html += '<li>Timeline steps: ' + c.timeline.entries.length + '</li>';
|
|
4666
|
-
html += '<li>Diagnostics: ' + c.diagnostics.map((d) => d.message).join('; ') + '</li></ul>';
|
|
4673
|
+
let html = '<h3>Case ' + escapeHtml(c.id) + '</h3><ul>';
|
|
4674
|
+
if (c.failureDiff) html += '<li>Diff errors: ' + escapeHtml(c.failureDiff.summary.errors) + '</li>';
|
|
4675
|
+
if (c.timeline) html += '<li>Timeline steps: ' + escapeHtml(c.timeline.entries.length) + '</li>';
|
|
4676
|
+
html += '<li>Diagnostics: ' + escapeHtml(c.diagnostics.map((d) => d.message).join('; ')) + '</li></ul>';
|
|
4667
4677
|
return html;
|
|
4668
4678
|
}).join('');
|
|
4669
|
-
return '<section><h2>Suite: ' + data.suiteName + ' (' + data.status + ')</h2>' +
|
|
4670
|
-
'<p>Passed ' + data.summary.passed + ', failed ' + data.summary.failed + '</p>' +
|
|
4679
|
+
return '<section><h2>Suite: ' + escapeHtml(data.suiteName) + ' (' + escapeHtml(data.status) + ')</h2>' +
|
|
4680
|
+
'<p>Passed ' + escapeHtml(data.summary.passed) + ', failed ' + escapeHtml(data.summary.failed) + '</p>' +
|
|
4671
4681
|
'<table><thead><tr><th>Case</th><th>Status</th><th>Message</th><th>Tool path</th><th>Observations</th></tr></thead><tbody>' +
|
|
4672
4682
|
rows + '</tbody></table>' +
|
|
4673
4683
|
'<section><h2>Failure detail</h2>' + (detail || '<p class="pass">No failures</p>') + '</section>' +
|
|
4674
|
-
'<section><h2>CI artifacts</h2><p>' + (data.ciArtifactsDir || 'n/a') + '</p></section>' +
|
|
4675
|
-
'<section><h2>Bundle export</h2><p>' + data.bundleExportHint + '</p></section>';
|
|
4684
|
+
'<section><h2>CI artifacts</h2><p>' + escapeHtml(data.ciArtifactsDir || 'n/a') + '</p></section>' +
|
|
4685
|
+
'<section><h2>Bundle export</h2><p>' + escapeHtml(data.bundleExportHint) + '</p></section>';
|
|
4676
4686
|
}
|
|
4677
4687
|
|
|
4678
4688
|
async function load() {
|
|
@@ -4688,8 +4698,8 @@ var viewerIndexHtml = `<!DOCTYPE html>
|
|
|
4688
4698
|
if (mode === "workspace") {
|
|
4689
4699
|
nav.innerHTML = '<a href="/api/workspace">/api/workspace</a>';
|
|
4690
4700
|
const data = await fetch("/api/workspace").then((r) => r.json());
|
|
4691
|
-
content.innerHTML = '<section><h2>Workspace: ' + (data.project || 'workspace') + '</h2>' +
|
|
4692
|
-
'<p>Runs: ' + data.runs.length + '</p><pre>' + JSON.stringify(data, null, 2) + '</pre></section>';
|
|
4701
|
+
content.innerHTML = '<section><h2>Workspace: ' + escapeHtml(data.project || 'workspace') + '</h2>' +
|
|
4702
|
+
'<p>Runs: ' + escapeHtml(data.runs.length) + '</p><pre>' + escapeHtml(JSON.stringify(data, null, 2)) + '</pre></section>';
|
|
4693
4703
|
return;
|
|
4694
4704
|
}
|
|
4695
4705
|
nav.innerHTML = '<a href="/api/traces">/api/traces</a> \xB7 <a href="/api/sessions">/api/sessions</a>';
|