This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/src/dashboard/templates/upgrade_queue.html
Alexander Payne 5f9bbb8435 feat: add task queue with human-in-the-loop approval + work orders + UI bug fixes
Task Queue system:
- New /tasks page with three-column layout (Pending/Active/Completed)
- Full CRUD API at /api/tasks with approve/veto/modify/pause/cancel/retry
- SQLite persistence in task_queue table
- WebSocket live updates via ws_manager
- Create task modal with agent assignment and priority
- Auto-approve rules for low-risk tasks
- HTMX polling for real-time column updates
- HOME TASK buttons now link to task queue with agent pre-selected
- MARKET HIRE buttons link to task queue with agent pre-selected

Work Order system:
- External submission API for agents/users (POST /work-orders/submit)
- Risk scoring and configurable auto-execution thresholds
- Dashboard at /work-orders/queue with approve/reject/execute flow
- Integration with swarm task system for execution

UI & Dashboard bug fixes:
- EVENTS: add startup event so page is never empty
- LEDGER: fix empty filter params in URL
- MISSION CONTROL: LLM backend and model now read from /health
- MISSION CONTROL: agent count fallback to /swarm/agents
- SWARM: HTMX fallback loads initial data if WebSocket is slow
- MEMORY: add edit/delete buttons for personal facts
- UPGRADES: add empty state guidance with links
- BRIEFING: add regenerate button and POST /briefing/regenerate endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:27:08 -05:00

295 lines
7.2 KiB
HTML

{% extends "base.html" %}
{% block title %}Upgrade Queue - Timmy Time{% endblock %}
{% block content %}
<div class="mc-panel">
<div class="mc-panel-header">
<h1 class="page-title">Upgrade Queue</h1>
<p class="mc-text-secondary">Review and approve self-modification proposals</p>
</div>
<!-- Pending Upgrades -->
<div class="mc-section">
<h2 class="mc-section-title">
Pending Upgrades
{% if pending_count > 0 %}
<span class="mc-badge mc-badge-warning">{{ pending_count }}</span>
{% endif %}
</h2>
{% if pending %}
<div class="upgrades-list">
{% for upgrade in pending %}
<div class="upgrade-card upgrade-pending" data-id="{{ upgrade.id }}">
<div class="upgrade-header">
<h3>{{ upgrade.description }}</h3>
<span class="mc-badge mc-badge-warning">PENDING</span>
</div>
<div class="upgrade-meta">
<span class="upgrade-branch">Branch: {{ upgrade.branch_name }}</span>
<span class="upgrade-time">Proposed: {{ upgrade.proposed_at[11:16] }}</span>
</div>
<div class="upgrade-files">
Files: {{ upgrade.files_changed|join(', ') }}
</div>
<div class="upgrade-test-status">
{% if upgrade.test_passed %}
<span class="test-passed">✓ Tests passed</span>
{% else %}
<span class="test-failed">✗ Tests failed</span>
{% endif %}
</div>
<div class="upgrade-actions">
<button class="mc-btn mc-btn-primary" onclick="approveUpgrade('{{ upgrade.id }}')">
Approve
</button>
<button class="mc-btn" onclick="rejectUpgrade('{{ upgrade.id }}')">
Reject
</button>
<a href="/self-modify/queue/{{ upgrade.id }}/diff" class="mc-btn mc-btn-secondary">
View Diff
</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="mc-empty-state" style="padding:2rem; text-align:center;">
<p>No pending upgrades.</p>
<p class="mc-text-secondary" style="margin-bottom:1rem;">Upgrades are proposed by the self-modification system when Timmy identifies improvements. You can also trigger them via work orders or the task queue.</p>
<div style="display:flex; gap:0.75rem; justify-content:center; flex-wrap:wrap;">
<a href="/work-orders/queue" class="mc-btn mc-btn-secondary" style="text-decoration:none;">View Work Orders</a>
<a href="/tasks" class="mc-btn mc-btn-secondary" style="text-decoration:none;">View Task Queue</a>
</div>
</div>
{% endif %}
</div>
<!-- Approved (Waiting to Apply) -->
{% if approved %}
<div class="mc-section">
<h2 class="mc-section-title">Approved (Ready to Apply)</h2>
<div class="upgrades-list">
{% for upgrade in approved %}
<div class="upgrade-card upgrade-approved">
<div class="upgrade-header">
<h3>{{ upgrade.description }}</h3>
<span class="mc-badge mc-badge-success">APPROVED</span>
</div>
<div class="upgrade-actions">
<button class="mc-btn mc-btn-primary" onclick="applyUpgrade('{{ upgrade.id }}')">
Apply Now
</button>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<!-- History -->
<div class="mc-section">
<h2 class="mc-section-title">History</h2>
{% if applied %}
<h4>Applied</h4>
<div class="upgrades-list upgrades-history">
{% for upgrade in applied %}
<div class="upgrade-card upgrade-applied">
<span class="upgrade-desc">{{ upgrade.description }}</span>
<span class="mc-badge mc-badge-success">APPLIED</span>
<span class="upgrade-time">{{ upgrade.applied_at[11:16] if upgrade.applied_at else '' }}</span>
</div>
{% endfor %}
</div>
{% endif %}
{% if rejected %}
<h4>Rejected</h4>
<div class="upgrades-list upgrades-history">
{% for upgrade in rejected %}
<div class="upgrade-card upgrade-rejected">
<span class="upgrade-desc">{{ upgrade.description }}</span>
<span class="mc-badge mc-badge-secondary">REJECTED</span>
</div>
{% endfor %}
</div>
{% endif %}
{% if failed %}
<h4>Failed</h4>
<div class="upgrades-list upgrades-history">
{% for upgrade in failed %}
<div class="upgrade-card upgrade-failed">
<span class="upgrade-desc">{{ upgrade.description }}</span>
<span class="mc-badge mc-badge-danger">FAILED</span>
<span class="upgrade-error" title="{{ upgrade.error_message }}">⚠️</span>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div>
<script>
async function approveUpgrade(id) {
if (!confirm('Approve this upgrade?')) return;
const response = await fetch(`/self-modify/queue/${id}/approve`, {
method: 'POST',
});
if (response.ok) {
window.location.reload();
} else {
alert('Failed to approve: ' + await response.text());
}
}
async function rejectUpgrade(id) {
if (!confirm('Reject this upgrade? The branch will be deleted.')) return;
const response = await fetch(`/self-modify/queue/${id}/reject`, {
method: 'POST',
});
if (response.ok) {
window.location.reload();
} else {
alert('Failed to reject: ' + await response.text());
}
}
async function applyUpgrade(id) {
if (!confirm('Apply this upgrade? This will merge to main.')) return;
const response = await fetch(`/self-modify/queue/${id}/apply`, {
method: 'POST',
});
if (response.ok) {
alert('Upgrade applied successfully!');
window.location.reload();
} else {
const error = await response.text();
alert('Failed to apply: ' + error);
}
}
</script>
<style>
.mc-section {
margin-bottom: 2rem;
}
.mc-section-title {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.upgrades-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.upgrade-card {
background: rgba(10, 15, 30, 0.6);
border: 1px solid var(--mc-border);
border-radius: 0.5rem;
padding: 1rem;
}
.upgrade-pending {
border-left: 4px solid #ffc107;
}
.upgrade-approved {
border-left: 4px solid #17a2b8;
}
.upgrade-applied {
border-left: 4px solid #28a745;
}
.upgrade-rejected {
border-left: 4px solid #6c757d;
}
.upgrade-failed {
border-left: 4px solid #dc3545;
}
.upgrade-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.5rem;
}
.upgrade-header h3 {
margin: 0;
font-size: 1.1rem;
}
.upgrade-meta {
display: flex;
gap: 1rem;
font-size: 0.85rem;
color: var(--mc-text-secondary);
margin-bottom: 0.5rem;
}
.upgrade-files {
font-size: 0.9rem;
margin-bottom: 0.5rem;
font-family: monospace;
}
.upgrade-test-status {
margin-bottom: 0.75rem;
}
.test-passed {
color: #28a745;
}
.test-failed {
color: #dc3545;
}
.upgrade-actions {
display: flex;
gap: 0.5rem;
}
.upgrades-history .upgrade-card {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.75rem 1rem;
}
.upgrade-desc {
flex: 1;
}
.upgrade-time {
font-size: 0.85rem;
color: var(--mc-text-secondary);
}
.upgrade-error {
color: #dc3545;
cursor: help;
}
</style>
{% endblock %}