Skip to content

Commit 4078bef

Browse files
Merge branch 'main' into feat/ci-optimization-and-instructions
2 parents d7b9c7b + 584a2db commit 4078bef

File tree

8 files changed

+314
-81
lines changed

8 files changed

+314
-81
lines changed

packages/agent-os-vscode/src/views/auditLogView.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ class AuditLogItem extends vscode.TreeItem {
4444
this.tooltip = AuditLogItem.formatTooltip(entry);
4545
this.description = AuditLogItem.formatTime(entry.timestamp);
4646
this.iconPath = AuditLogItem.getIcon(entry.type);
47+
this.accessibilityInformation = {
48+
label: AuditLogItem.formatAccessibilityLabel(entry),
49+
role: 'treeitem'
50+
};
4751

4852
if (entry.file) {
4953
this.command = {
@@ -72,10 +76,18 @@ class AuditLogItem extends vscode.TreeItem {
7276
private static formatTooltip(entry: AuditEntry): string {
7377
let tooltip = `Type: ${entry.type}\n`;
7478
tooltip += `Time: ${entry.timestamp.toLocaleString()}\n`;
75-
if (entry.file) tooltip += `File: ${entry.file}\n`;
76-
if (entry.language) tooltip += `Language: ${entry.language}\n`;
77-
if (entry.reason) tooltip += `Reason: ${entry.reason}\n`;
78-
if (entry.code) tooltip += `\nCode:\n${entry.code.substring(0, 100)}...`;
79+
if (entry.file) {
80+
tooltip += `File: ${entry.file}\n`;
81+
}
82+
if (entry.language) {
83+
tooltip += `Language: ${entry.language}\n`;
84+
}
85+
if (entry.reason) {
86+
tooltip += `Reason: ${entry.reason}\n`;
87+
}
88+
if (entry.code) {
89+
tooltip += `\nCode:\n${entry.code.substring(0, 100)}...`;
90+
}
7991
return tooltip;
8092
}
8193

@@ -86,12 +98,30 @@ class AuditLogItem extends vscode.TreeItem {
8698
const hours = Math.floor(diff / 3600000);
8799
const days = Math.floor(diff / 86400000);
88100

89-
if (minutes < 1) return 'just now';
90-
if (minutes < 60) return `${minutes}m ago`;
91-
if (hours < 24) return `${hours}h ago`;
101+
if (minutes < 1) {
102+
return 'just now';
103+
}
104+
if (minutes < 60) {
105+
return `${minutes}m ago`;
106+
}
107+
if (hours < 24) {
108+
return `${hours}h ago`;
109+
}
92110
return `${days}d ago`;
93111
}
94112

113+
private static formatAccessibilityLabel(entry: AuditEntry): string {
114+
const parts = [AuditLogItem.formatLabel(entry)];
115+
parts.push(`Recorded ${entry.timestamp.toLocaleString()}`);
116+
if (entry.file) {
117+
parts.push(`File ${entry.file}`);
118+
}
119+
if (entry.reason) {
120+
parts.push(`Reason ${entry.reason}`);
121+
}
122+
return parts.join('. ');
123+
}
124+
95125
private static getIcon(type: AuditEntry['type']): vscode.ThemeIcon {
96126
switch (type) {
97127
case 'blocked':

packages/agent-os-vscode/src/views/kernelDebuggerView.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ export class DebuggerItem extends vscode.TreeItem {
297297
public readonly data?: Record<string, any>
298298
) {
299299
super(label, collapsibleState);
300+
this.accessibilityInformation = {
301+
label: DebuggerItem.getAccessibilityLabel(label, data),
302+
role: 'treeitem'
303+
};
300304

301305
// Set icon based on context
302306
if (data?.icon) {
@@ -330,6 +334,19 @@ export class DebuggerItem extends vscode.TreeItem {
330334
};
331335
}
332336
}
337+
338+
private static getAccessibilityLabel(label: string, data?: Record<string, any>): string {
339+
const sanitizedLabel = label
340+
.replace(/[^\x20-\x7E]+/g, ' ')
341+
.replace(/\s+/g, ' ')
342+
.trim();
343+
344+
if (data?.type === 'agent' && data.agent) {
345+
return `${data.agent.name}. Status ${data.agent.status}. ${data.agent.currentTask ? `Current task ${data.agent.currentTask}.` : ''}`.trim();
346+
}
347+
348+
return sanitizedLabel || 'Debugger item';
349+
}
333350
}
334351

335352
/**
@@ -419,7 +436,9 @@ export class MemoryBrowserProvider implements vscode.TreeDataProvider<MemoryItem
419436

420437
for (const part of parts) {
421438
const child = current.children?.find(c => c.name === part);
422-
if (!child) return null;
439+
if (!child) {
440+
return null;
441+
}
423442
current = child;
424443
}
425444

@@ -477,6 +496,12 @@ export class MemoryItem extends vscode.TreeItem {
477496

478497
this.contextValue = nodeType;
479498
this.tooltip = path;
499+
this.accessibilityInformation = {
500+
label: nodeType === 'directory'
501+
? `Directory ${label}. Path ${path}`
502+
: `File ${label}. Path ${path}`,
503+
role: 'treeitem'
504+
};
480505

481506
if (nodeType === 'file') {
482507
this.command = {

packages/agent-os-vscode/src/views/policiesView.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class PolicyItem extends vscode.TreeItem {
4242

4343
this.description = enabled ? `${severity}` : 'disabled';
4444
this.tooltip = `${name}\nSeverity: ${severity}\nStatus: ${enabled ? 'Enabled' : 'Disabled'}`;
45+
this.accessibilityInformation = {
46+
label: `${name}. Severity ${severity}. ${enabled ? 'Enabled' : 'Disabled'}.`,
47+
role: 'treeitem'
48+
};
4549

4650
if (enabled) {
4751
this.iconPath = this.getSeverityIcon(severity);

packages/agent-os-vscode/src/views/statsView.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ class StatsItem extends vscode.TreeItem {
5151
this.description = value;
5252
this.tooltip = `${label}: ${value}`;
5353
this.iconPath = this.getIcon(type);
54+
this.accessibilityInformation = {
55+
label: `${label}: ${value}`,
56+
role: 'treeitem'
57+
};
5458
}
5559

5660
private getIcon(type: string): vscode.ThemeIcon {

packages/agent-os-vscode/src/webviews/metricsDashboard/MetricsDashboardPanel.ts

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import * as vscode from 'vscode';
1111
import * as crypto from 'crypto';
12-
import { AuditLogger, AuditEntry } from '../../auditLogger';
12+
import { AuditLogger } from '../../auditLogger';
1313

1414
interface MetricsData {
1515
blockedToday: number;
@@ -420,16 +420,29 @@ export class MetricsDashboardPanel {
420420
@media (max-width: 800px) {
421421
.two-col { grid-template-columns: 1fr; }
422422
}
423+
.sr-only {
424+
position: absolute;
425+
width: 1px;
426+
height: 1px;
427+
padding: 0;
428+
margin: -1px;
429+
overflow: hidden;
430+
clip: rect(0, 0, 0, 0);
431+
white-space: nowrap;
432+
border: 0;
433+
}
423434
</style>
424435
</head>
425436
<body>
437+
<main aria-labelledby="metrics-title">
426438
<div class="header">
427439
<h1>
428440
<span class="status-dot active"></span>
429-
Agent OS Metrics Dashboard
441+
<span id="metrics-title">Agent OS Metrics Dashboard</span>
430442
</h1>
431-
<div class="controls">
432-
<select id="timeRange" onchange="setTimeRange(this.value)">
443+
<div class="controls" role="toolbar" aria-label="Metrics dashboard controls">
444+
<label class="sr-only" for="timeRange">Time range</label>
445+
<select id="timeRange" aria-label="Time range" onchange="setTimeRange(this.value)">
433446
<option value="today">Today</option>
434447
<option value="week">This Week</option>
435448
<option value="month">This Month</option>
@@ -441,50 +454,50 @@ export class MetricsDashboardPanel {
441454
</div>
442455
443456
<div class="grid">
444-
<div class="card danger">
457+
<div class="card danger" role="group" aria-label="Blocked operations today">
445458
<div class="card-title">Blocked Operations</div>
446459
<div class="card-value" id="blockedToday">0</div>
447460
<div class="card-subtitle">Today</div>
448461
</div>
449-
<div class="card warning">
462+
<div class="card warning" role="group" aria-label="Warnings today">
450463
<div class="card-title">Warnings</div>
451464
<div class="card-value" id="warningsToday">0</div>
452465
<div class="card-subtitle">Today</div>
453466
</div>
454-
<div class="card success">
467+
<div class="card success" role="group" aria-label="CMVK reviews today">
455468
<div class="card-title">CMVK Reviews</div>
456469
<div class="card-value" id="cmvkReviewsToday">0</div>
457470
<div class="card-subtitle">Today</div>
458471
</div>
459-
<div class="card">
472+
<div class="card" role="group" aria-label="Total events">
460473
<div class="card-title">Total Events</div>
461474
<div class="card-value" id="totalLogs">0</div>
462475
<div class="card-subtitle">All time</div>
463476
</div>
464477
</div>
465478
466479
<div class="two-col">
467-
<div class="chart-container">
480+
<section class="chart-container" aria-label="Activity by hour">
468481
<div class="chart-title">📊 Activity by Hour</div>
469-
<div class="bar-chart" id="activityChart"></div>
482+
<div class="bar-chart" id="activityChart" role="img" aria-label="Activity by hour chart"></div>
470483
<div class="bar-labels">
471484
<span>12 AM</span>
472485
<span>6 AM</span>
473486
<span>12 PM</span>
474487
<span>6 PM</span>
475488
<span>11 PM</span>
476489
</div>
477-
</div>
490+
</section>
478491
479-
<div class="chart-container">
492+
<section class="chart-container" aria-label="Top policy violations">
480493
<div class="chart-title">🛡️ Top Policy Violations</div>
481-
<div class="violations-list" id="topViolations">
494+
<div class="violations-list" id="topViolations" role="list" aria-live="polite">
482495
<p style="color: var(--vscode-descriptionForeground); text-align: center;">No violations recorded</p>
483496
</div>
484-
</div>
497+
</section>
485498
</div>
486499
487-
<div class="chart-container">
500+
<section class="chart-container" aria-label="Policy check latency">
488501
<div class="chart-title">⚡ Policy Check Latency</div>
489502
<div class="latency-grid">
490503
<div class="latency-item">
@@ -506,7 +519,7 @@ export class MetricsDashboardPanel {
506519
<p style="text-align: center; font-size: 11px; color: var(--vscode-descriptionForeground); margin-top: 15px;">
507520
Target: &lt;50ms for P99 ✓
508521
</p>
509-
</div>
522+
</section>
510523
511524
<script nonce="${nonce}">
512525
const vscode = acquireVsCodeApi();
@@ -526,9 +539,10 @@ export class MetricsDashboardPanel {
526539
function updateChart(data) {
527540
const chart = document.getElementById('activityChart');
528541
const max = Math.max(...data, 1);
542+
chart.setAttribute('aria-label', 'Activity by hour. ' + data.map((value, hour) => hour + ':00 has ' + value + ' events').join('. '));
529543
530544
chart.innerHTML = data.map((value, i) =>
531-
\`<div class="bar" style="height: \${(value / max) * 100}%" data-value="\${value}"></div>\`
545+
\`<div class="bar" style="height: \${(value / max) * 100}%" data-value="\${value}" aria-hidden="true"></div>\`
532546
).join('');
533547
}
534548
@@ -541,7 +555,7 @@ export class MetricsDashboardPanel {
541555
}
542556
543557
container.innerHTML = violations.map(v => \`
544-
<div class="violation-item">
558+
<div class="violation-item" role="listitem">
545559
<span class="violation-name">
546560
<span style="color: #dc3545;">⚠️</span>
547561
\${v.name.replace(/_/g, ' ')}
@@ -567,9 +581,15 @@ export class MetricsDashboardPanel {
567581
568582
updateChart(m.activityByHour);
569583
updateViolations(m.topViolations);
584+
document.getElementById('metricsAnnouncer').textContent =
585+
'Metrics updated. ' + m.blockedToday + ' blocked operations, ' +
586+
m.warningsToday + ' warnings, and ' +
587+
m.cmvkReviewsToday + ' CMVK reviews.';
570588
}
571589
});
572590
</script>
591+
<div id="metricsAnnouncer" class="sr-only" aria-live="polite"></div>
592+
</main>
573593
</body>
574594
</html>`;
575595
}

packages/agent-os-vscode/src/webviews/onboarding/OnboardingPanel.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -419,29 +419,43 @@ export class OnboardingPanel {
419419
.tip strong {
420420
color: var(--vscode-foreground);
421421
}
422+
.sr-only {
423+
position: absolute;
424+
width: 1px;
425+
height: 1px;
426+
padding: 0;
427+
margin: -1px;
428+
overflow: hidden;
429+
clip: rect(0, 0, 0, 0);
430+
white-space: nowrap;
431+
border: 0;
432+
}
422433
</style>
423434
</head>
424435
<body>
425-
<div class="container">
426-
<div class="hero">
436+
<main class="container" aria-labelledby="onboarding-title">
437+
<div class="hero" role="banner">
427438
<div class="logo">🛡️</div>
428-
<h1>Welcome to Agent OS</h1>
439+
<h1 id="onboarding-title">Welcome to Agent OS</h1>
429440
<p>Kernel-level safety for autonomous AI agents</p>
430441
</div>
431442
432-
<div class="progress-container">
443+
<section class="progress-container" aria-labelledby="progress-heading">
433444
<div class="progress-header">
434-
<span class="progress-label">Getting Started</span>
435-
<span class="progress-count">${completedCount} of ${totalSteps} completed</span>
445+
<span class="progress-label" id="progress-heading">Getting Started</span>
446+
<span class="progress-count" id="progress-count" aria-live="polite">${completedCount} of ${totalSteps} completed</span>
436447
</div>
437-
<div class="progress-bar">
448+
<div class="progress-bar" role="progressbar" aria-label="Onboarding progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${progress}" aria-valuetext="${completedCount} of ${totalSteps} steps completed">
438449
<div class="progress-fill" style="width: ${progress}%"></div>
439450
</div>
440-
</div>
451+
</section>
441452
442-
<div class="steps" id="steps"></div>
453+
<section aria-labelledby="steps-heading">
454+
<h2 id="steps-heading" class="sr-only">Onboarding steps</h2>
455+
<div class="steps" id="steps" role="list"></div>
456+
</section>
443457
444-
<div class="footer">
458+
<footer class="footer">
445459
<div class="footer-links">
446460
<a href="https://github.com/microsoft/agent-governance-toolkit" target="_blank">📚 Documentation</a>
447461
<a href="https://github.com/microsoft/agent-governance-toolkit/issues" target="_blank">💬 Get Help</a>
@@ -451,8 +465,8 @@ export class OnboardingPanel {
451465
<button class="secondary" onclick="resetProgress()">Reset Progress</button>
452466
<button class="secondary" onclick="skipOnboarding()">Skip Onboarding</button>
453467
</div>
454-
</div>
455-
</div>
468+
</footer>
469+
</main>
456470
457471
<script nonce="${nonce}">
458472
const vscode = acquireVsCodeApi();
@@ -469,18 +483,18 @@ export class OnboardingPanel {
469483
<p class="step-description">\${step.description}</p>
470484
<div class="step-actions">
471485
\${step.action ? \`
472-
<button onclick="executeAction('\${step.action.command}')" \${step.completed ? 'disabled' : ''}>
486+
<button onclick="executeAction('\${step.action.command}')" aria-label="\${step.action.label}: \${step.title}" \${step.completed ? 'disabled' : ''}>
473487
\${step.action.label}
474488
</button>
475489
\` : ''}
476490
\${!step.completed ? \`
477-
<button class="secondary" onclick="completeStep('\${step.id}')">
491+
<button class="secondary" onclick="completeStep('\${step.id}')" aria-label="Mark \${step.title} complete">
478492
Mark Complete
479493
</button>
480494
\` : ''}
481495
</div>
482496
\${index === 0 ? \`
483-
<div class="tip">
497+
<div class="tip" role="note">
484498
<strong>💡 Tip:</strong> Agent OS works with existing AI tools like GitHub Copilot,
485499
Cursor, and LangChain. It adds a safety layer without changing your workflow.
486500
</div>
@@ -522,6 +536,9 @@ export class OnboardingPanel {
522536
const progress = Math.round((completed / total) * 100);
523537
document.querySelector('.progress-fill').style.width = progress + '%';
524538
document.querySelector('.progress-count').textContent = completed + ' of ' + total + ' completed';
539+
const progressBar = document.querySelector('.progress-bar');
540+
progressBar.setAttribute('aria-valuenow', String(progress));
541+
progressBar.setAttribute('aria-valuetext', completed + ' of ' + total + ' steps completed');
525542
}
526543
527544
window.addEventListener('message', event => {

0 commit comments

Comments
 (0)