feat: add agent history persistence and history view page

- Add AgentHistory class to persist completed agent runs to disk
- Store full message logs in JSON files with index for fast lookups
- Add /api/history and /api/history/{task_id} endpoints
- Create history page in dashboard showing past agent runs
- Add History link to navigation menu
- Update agent detail page to fall back to history for completed runs
- Display status badges (Success/Failed/Timeout) on history cards

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CI System
2025-12-11 07:42:12 -07:00
parent 3bd1b0eabd
commit dbf118a8f8
35 changed files with 697 additions and 84 deletions

131
agent.py
View File

@@ -73,6 +73,127 @@ class AgentTask:
with self._messages_lock:
return len(self.messages)
def to_history_dict(self) -> dict:
"""Convert task to a dict for history persistence."""
return {
"task_id": self.task_id,
"issue_id": self.issue_id,
"issue_number": self.issue_number,
"repo": self.repo,
"platform": self.platform,
"task_type": self.task_type,
"started_at": self.started_at.isoformat() if self.started_at else None,
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
"returncode": self.returncode,
"timed_out": self.timed_out,
"messages": self.get_messages(),
}
class AgentHistory:
"""Manages persistent history of agent runs."""
def __init__(self, history_dir: str = "/opt/agent_runner/history"):
self.history_dir = Path(history_dir)
self.history_dir.mkdir(parents=True, exist_ok=True)
self._index_file = self.history_dir / "index.json"
self._index_lock = threading.Lock()
self._load_index()
def _load_index(self):
"""Load or create the history index."""
if self._index_file.exists():
try:
with open(self._index_file, "r") as f:
self._index = json.load(f)
except (json.JSONDecodeError, IOError):
self._index = {"runs": []}
else:
self._index = {"runs": []}
def _save_index(self):
"""Save the history index."""
try:
with open(self._index_file, "w") as f:
json.dump(self._index, f, indent=2)
except IOError as e:
logger.error(f"Failed to save history index: {e}")
def save_run(self, task: "AgentTask"):
"""Save a completed agent run to history."""
run_data = task.to_history_dict()
run_id = task.task_id
# Save full run data to individual file
run_file = self.history_dir / f"{run_id}.json"
try:
with open(run_file, "w") as f:
json.dump(run_data, f, indent=2)
except IOError as e:
logger.error(f"Failed to save run {run_id}: {e}")
return
# Update index with summary
with self._index_lock:
summary = {
"task_id": task.task_id,
"issue_id": task.issue_id,
"repo": task.repo,
"task_type": task.task_type,
"started_at": run_data["started_at"],
"completed_at": run_data["completed_at"],
"returncode": task.returncode,
"timed_out": task.timed_out,
"message_count": len(run_data["messages"]),
}
# Add to front of list (most recent first)
self._index["runs"].insert(0, summary)
# Keep only last 100 runs in index
if len(self._index["runs"]) > 100:
self._index["runs"] = self._index["runs"][:100]
self._save_index()
logger.info(f"Saved history for run {run_id}")
def get_runs(self, limit: int = 50, offset: int = 0) -> list[dict]:
"""Get list of recent runs (summaries only)."""
with self._index_lock:
return self._index["runs"][offset:offset + limit]
def get_run(self, task_id: str) -> Optional[dict]:
"""Get full run data by task ID."""
run_file = self.history_dir / f"{task_id}.json"
if not run_file.exists():
return None
try:
with open(run_file, "r") as f:
return json.load(f)
except (json.JSONDecodeError, IOError) as e:
logger.error(f"Failed to load run {task_id}: {e}")
return None
def delete_run(self, task_id: str) -> bool:
"""Delete a run from history."""
run_file = self.history_dir / f"{task_id}.json"
# Remove from index
with self._index_lock:
self._index["runs"] = [r for r in self._index["runs"] if r["task_id"] != task_id]
self._save_index()
# Delete file
try:
if run_file.exists():
run_file.unlink()
return True
except IOError as e:
logger.error(f"Failed to delete run {task_id}: {e}")
return False
class AgentPool:
"""Manages a pool of Claude Code agent processes."""
@@ -88,6 +209,7 @@ class AgentPool:
claude_flags: list[str] = None,
on_complete: Callable[[AgentTask], None] = None,
timeout_seconds: int = 1800, # 30 minutes default
history_dir: str = "/opt/agent_runner/history",
):
self.max_agents = max_agents
self.claude_command = claude_command
@@ -100,6 +222,9 @@ class AgentPool:
self._monitor_thread: Optional[threading.Thread] = None
self._shutdown_event = threading.Event()
# History persistence
self.history = AgentHistory(history_dir)
def start(self):
"""Start the agent pool monitor."""
self._shutdown_event.clear()
@@ -330,6 +455,12 @@ class AgentPool:
stderr_preview = task.stderr[:500] if task.stderr else ""
logger.warning(f"Agent {task.task_id} stderr: {stderr_preview}")
# Save to history before callback
try:
self.history.save_run(task)
except Exception as e:
logger.error(f"Failed to save history for {task.task_id}: {e}")
if self.on_complete:
try:
self.on_complete(task)

View File

@@ -379,6 +379,27 @@ class DashboardAPIHandler(BaseHTTPRequestHandler):
else:
self.send_error_json(400, "MISSING_TASK_ID", "Task ID required")
# GET /api/history - Agent run history
elif path == "/api/history":
limit = int(query.get("limit", [50])[0])
offset = int(query.get("offset", [0])[0])
runs = self.runner.agent_pool.history.get_runs(limit, offset)
self.send_json({"runs": runs, "limit": limit, "offset": offset})
# GET /api/history/{task_id} - Single history run
elif path.startswith("/api/history/"):
task_id = path.split("/")[-1]
run = self.runner.agent_pool.history.get_run(task_id)
if run:
self.send_json(run)
else:
# Also check if it's an active task
output = self.runner.agent_pool.get_task_output(task_id)
if output:
self.send_json(output)
else:
self.send_error_json(404, "NOT_FOUND", f"Run {task_id} not found")
# GET /api/config - Configuration
elif path == "/api/config":
self.send_json(self.dashboard_api.get_config())

View File

@@ -1,5 +1,5 @@
// API Client for Agent Runner Dashboard
import type { User, DashboardStatus, Issue, Build, Config, AgentOutput } from './types';
import type { User, DashboardStatus, Issue, Build, Config, AgentOutput, HistoryResponse, HistoryRun } from './types';
class ApiError extends Error {
constructor(
@@ -144,6 +144,21 @@ export const api = {
body: JSON.stringify(updates)
});
return handleResponse<{ success: boolean }>(response);
},
// History
async getHistory(limit: number = 50, offset: number = 0): Promise<HistoryResponse> {
const response = await fetch(`/api/history?limit=${limit}&offset=${offset}`, {
credentials: 'include'
});
return handleResponse<HistoryResponse>(response);
},
async getHistoryRun(taskId: string): Promise<HistoryRun> {
const response = await fetch(`/api/history/${taskId}`, {
credentials: 'include'
});
return handleResponse<HistoryRun>(response);
}
};

View File

@@ -153,3 +153,28 @@ export interface AgentOutput {
message_count: number;
messages: StreamMessage[];
}
// History types
export interface HistoryRunSummary {
task_id: string;
issue_id: string;
repo: string;
task_type: string;
started_at: string;
completed_at: string;
returncode: number;
timed_out: boolean;
message_count: number;
}
export interface HistoryRun extends HistoryRunSummary {
issue_number: number;
platform: string;
messages: StreamMessage[];
}
export interface HistoryResponse {
runs: HistoryRunSummary[];
limit: number;
offset: number;
}

View File

@@ -10,6 +10,7 @@
const navItems = [
{ path: '/', label: 'Dashboard', icon: 'dashboard' },
{ path: '/agents', label: 'Agents', icon: 'smart_toy' },
{ path: '/history', label: 'History', icon: 'history' },
{ path: '/issues', label: 'Issues', icon: 'assignment' },
{ path: '/builds', label: 'Builds', icon: 'build' },
{ path: '/config', label: 'Config', icon: 'settings' }

View File

@@ -14,12 +14,13 @@
let error = $state<string | null>(null);
let completed = $state(false);
let returncode = $state<number | null>(null);
let isHistorical = $state(false);
let eventSource: EventSource | null = null;
let messagesContainer: HTMLElement;
let autoScroll = $state(true);
onMount(() => {
connectStream();
loadTask();
});
onDestroy(() => {
@@ -28,56 +29,76 @@
}
});
function connectStream() {
async function loadTask() {
loading = true;
error = null;
// First fetch existing messages
api.getAgentOutput(taskId).then(output => {
try {
// First try to get active agent output
const output = await api.getAgentOutput(taskId);
issueId = output.issue_id;
repo = output.repo;
taskType = output.task_type;
started = output.started;
messages = output.messages;
loading = false;
isHistorical = false;
// Then connect SSE for real-time updates
eventSource = api.createAgentStream(taskId);
eventSource.onmessage = (event) => {
try {
const msg = JSON.parse(event.data) as StreamMessage;
messages = [...messages, msg];
if (autoScroll) {
scrollToBottom();
}
} catch (e) {
console.error('Failed to parse SSE message:', e);
}
};
eventSource.addEventListener('complete', (event) => {
// Connect SSE for real-time updates
connectStream();
} catch (err) {
// If not found as active, try history
try {
const historyRun = await api.getHistoryRun(taskId);
issueId = historyRun.issue_id;
repo = historyRun.repo;
taskType = historyRun.task_type;
started = historyRun.started_at;
messages = historyRun.messages;
completed = true;
try {
const data = JSON.parse((event as MessageEvent).data);
returncode = data.returncode ?? null;
} catch (e) {
// ignore
}
eventSource?.close();
});
returncode = historyRun.returncode;
isHistorical = true;
loading = false;
} catch (histErr) {
loading = false;
error = 'Task not found';
}
}
}
eventSource.onerror = () => {
// Connection lost - task may have completed
if (!completed) {
completed = true;
function connectStream() {
eventSource = api.createAgentStream(taskId);
eventSource.onmessage = (event) => {
try {
const msg = JSON.parse(event.data) as StreamMessage;
messages = [...messages, msg];
if (autoScroll) {
scrollToBottom();
}
eventSource?.close();
};
}).catch(err => {
loading = false;
error = err instanceof Error ? err.message : 'Failed to load agent output';
} catch (e) {
console.error('Failed to parse SSE message:', e);
}
};
eventSource.addEventListener('complete', (event) => {
completed = true;
try {
const data = JSON.parse((event as MessageEvent).data);
returncode = data.returncode ?? null;
} catch (e) {
// ignore
}
eventSource?.close();
});
eventSource.onerror = () => {
// Connection lost - task may have completed
if (!completed) {
completed = true;
}
eventSource?.close();
};
}
function scrollToBottom() {

View File

@@ -0,0 +1,350 @@
<script lang="ts">
import { onMount } from 'svelte';
import { api } from '$lib/api/client';
import type { HistoryRunSummary } from '$lib/api/types';
let runs: HistoryRunSummary[] = $state([]);
let loading = $state(true);
let error = $state<string | null>(null);
let hasMore = $state(true);
let offset = $state(0);
const limit = 25;
onMount(() => {
loadHistory();
});
async function loadHistory(append = false) {
if (!append) {
loading = true;
offset = 0;
}
error = null;
try {
const response = await api.getHistory(limit, append ? offset : 0);
if (append) {
runs = [...runs, ...response.runs];
} else {
runs = response.runs;
}
hasMore = response.runs.length === limit;
offset = runs.length;
} catch (err) {
error = err instanceof Error ? err.message : 'Failed to load history';
} finally {
loading = false;
}
}
function loadMore() {
loadHistory(true);
}
function formatDate(dateStr: string): string {
if (!dateStr) return '-';
return new Date(dateStr).toLocaleString();
}
function formatDuration(start: string, end: string): string {
if (!start || !end) return '-';
const ms = new Date(end).getTime() - new Date(start).getTime();
const secs = Math.floor(ms / 1000);
const mins = Math.floor(secs / 60);
if (mins > 0) {
return `${mins}m ${secs % 60}s`;
}
return `${secs}s`;
}
function getStatusClass(run: HistoryRunSummary): string {
if (run.timed_out) return 'timeout';
if (run.returncode === 0) return 'success';
return 'error';
}
function getStatusText(run: HistoryRunSummary): string {
if (run.timed_out) return 'Timeout';
if (run.returncode === 0) return 'Success';
return `Failed (${run.returncode})`;
}
</script>
<div class="history-page">
<div class="header">
<h1>Agent History</h1>
<button class="refresh-button" onclick={() => loadHistory()} disabled={loading}>
<span class="material-icons" class:spinning={loading}>refresh</span>
Refresh
</button>
</div>
{#if loading && runs.length === 0}
<div class="loading">
<span class="material-icons spinning">sync</span>
<p>Loading history...</p>
</div>
{:else if error}
<div class="error-state">
<span class="material-icons">error</span>
<p>{error}</p>
<button onclick={() => loadHistory()}>Retry</button>
</div>
{:else if runs.length === 0}
<div class="empty-state">
<span class="material-icons">history</span>
<h2>No History Yet</h2>
<p>Agent runs will appear here once completed</p>
</div>
{:else}
<div class="history-list">
{#each runs as run}
<a href="/agents/{run.task_id}" class="history-card">
<div class="card-header">
<span class="issue-id">{run.issue_id}</span>
<span class="status status-{getStatusClass(run)}">{getStatusText(run)}</span>
</div>
<div class="card-body">
<div class="meta-row">
<span class="task-type">{run.task_type}</span>
<span class="repo">
<span class="material-icons">folder</span>
{run.repo}
</span>
</div>
<div class="meta-row">
<span class="time">
<span class="material-icons">schedule</span>
{formatDate(run.started_at)}
</span>
<span class="duration">
<span class="material-icons">timer</span>
{formatDuration(run.started_at, run.completed_at)}
</span>
</div>
<div class="message-count">
<span class="material-icons">chat</span>
{run.message_count} messages
</div>
</div>
</a>
{/each}
</div>
{#if hasMore}
<div class="load-more">
<button onclick={loadMore} disabled={loading}>
{#if loading}
<span class="material-icons spinning">sync</span>
{:else}
Load More
{/if}
</button>
</div>
{/if}
{/if}
</div>
<style>
.history-page {
max-width: 1000px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
h1 {
font-size: 1.75rem;
font-weight: 400;
margin: 0;
}
.refresh-button {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 4px;
background: white;
font-size: 0.875rem;
cursor: pointer;
}
.refresh-button:hover:not(:disabled) {
background-color: rgba(0, 0, 0, 0.04);
}
.refresh-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.history-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.history-card {
display: block;
background: white;
border-radius: 8px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
text-decoration: none;
color: inherit;
transition: box-shadow 0.2s, transform 0.2s;
}
.history-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.issue-id {
font-size: 1.125rem;
font-weight: 500;
color: var(--mdc-theme-primary);
}
.status {
padding: 4px 10px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 500;
}
.status-success {
background-color: #e8f5e9;
color: #2e7d32;
}
.status-error {
background-color: #ffebee;
color: #c62828;
}
.status-timeout {
background-color: #fff3e0;
color: #ef6c00;
}
.card-body {
display: flex;
flex-direction: column;
gap: 8px;
}
.meta-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.875rem;
color: rgba(0, 0, 0, 0.6);
}
.task-type {
text-transform: uppercase;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.5px;
color: var(--mdc-theme-primary);
}
.repo, .time, .duration, .message-count {
display: flex;
align-items: center;
gap: 4px;
}
.meta-row .material-icons,
.message-count .material-icons {
font-size: 16px;
}
.message-count {
font-size: 0.75rem;
color: rgba(0, 0, 0, 0.4);
}
.loading, .empty-state, .error-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 64px;
background: white;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
color: rgba(0, 0, 0, 0.6);
}
.empty-state .material-icons,
.loading .material-icons {
font-size: 48px;
color: rgba(0, 0, 0, 0.2);
margin-bottom: 16px;
}
.error-state .material-icons {
font-size: 48px;
color: #c62828;
margin-bottom: 16px;
}
.error-state button {
margin-top: 16px;
padding: 8px 16px;
border: 1px solid #c62828;
border-radius: 4px;
background: transparent;
color: #c62828;
cursor: pointer;
}
.load-more {
display: flex;
justify-content: center;
margin-top: 24px;
}
.load-more button {
padding: 12px 32px;
border: 1px solid var(--mdc-theme-primary);
border-radius: 4px;
background: transparent;
color: var(--mdc-theme-primary);
font-size: 0.875rem;
cursor: pointer;
}
.load-more button:hover:not(:disabled) {
background-color: rgba(25, 118, 210, 0.04);
}
.load-more button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.spinning {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>

View File

@@ -0,0 +1 @@
.history-page.svelte-1xl2tfr{max-width:1000px;margin:0 auto}.header.svelte-1xl2tfr{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}h1.svelte-1xl2tfr{font-size:1.75rem;font-weight:400;margin:0}.refresh-button.svelte-1xl2tfr{display:flex;align-items:center;gap:6px;padding:8px 16px;border:1px solid rgba(0,0,0,.2);border-radius:4px;background:#fff;font-size:.875rem;cursor:pointer}.refresh-button.svelte-1xl2tfr:hover:not(:disabled){background-color:#0000000a}.refresh-button.svelte-1xl2tfr:disabled{opacity:.5;cursor:not-allowed}.history-list.svelte-1xl2tfr{display:flex;flex-direction:column;gap:12px}.history-card.svelte-1xl2tfr{display:block;background:#fff;border-radius:8px;padding:16px;box-shadow:0 1px 3px #0000001a;text-decoration:none;color:inherit;transition:box-shadow .2s,transform .2s}.history-card.svelte-1xl2tfr:hover{box-shadow:0 4px 12px #00000026;transform:translateY(-2px)}.card-header.svelte-1xl2tfr{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.issue-id.svelte-1xl2tfr{font-size:1.125rem;font-weight:500;color:var(--mdc-theme-primary)}.status.svelte-1xl2tfr{padding:4px 10px;border-radius:12px;font-size:.75rem;font-weight:500}.status-success.svelte-1xl2tfr{background-color:#e8f5e9;color:#2e7d32}.status-error.svelte-1xl2tfr{background-color:#ffebee;color:#c62828}.status-timeout.svelte-1xl2tfr{background-color:#fff3e0;color:#ef6c00}.card-body.svelte-1xl2tfr{display:flex;flex-direction:column;gap:8px}.meta-row.svelte-1xl2tfr{display:flex;justify-content:space-between;align-items:center;font-size:.875rem;color:#0009}.task-type.svelte-1xl2tfr{text-transform:uppercase;font-size:.75rem;font-weight:600;letter-spacing:.5px;color:var(--mdc-theme-primary)}.repo.svelte-1xl2tfr,.time.svelte-1xl2tfr,.duration.svelte-1xl2tfr,.message-count.svelte-1xl2tfr{display:flex;align-items:center;gap:4px}.meta-row.svelte-1xl2tfr .material-icons:where(.svelte-1xl2tfr),.message-count.svelte-1xl2tfr .material-icons:where(.svelte-1xl2tfr){font-size:16px}.message-count.svelte-1xl2tfr{font-size:.75rem;color:#0006}.loading.svelte-1xl2tfr,.empty-state.svelte-1xl2tfr,.error-state.svelte-1xl2tfr{display:flex;flex-direction:column;align-items:center;padding:64px;background:#fff;border-radius:8px;box-shadow:0 1px 3px #0000001a;color:#0009}.empty-state.svelte-1xl2tfr .material-icons:where(.svelte-1xl2tfr),.loading.svelte-1xl2tfr .material-icons:where(.svelte-1xl2tfr){font-size:48px;color:#0003;margin-bottom:16px}.error-state.svelte-1xl2tfr .material-icons:where(.svelte-1xl2tfr){font-size:48px;color:#c62828;margin-bottom:16px}.error-state.svelte-1xl2tfr button:where(.svelte-1xl2tfr){margin-top:16px;padding:8px 16px;border:1px solid #c62828;border-radius:4px;background:transparent;color:#c62828;cursor:pointer}.load-more.svelte-1xl2tfr{display:flex;justify-content:center;margin-top:24px}.load-more.svelte-1xl2tfr button:where(.svelte-1xl2tfr){padding:12px 32px;border:1px solid var(--mdc-theme-primary);border-radius:4px;background:transparent;color:var(--mdc-theme-primary);font-size:.875rem;cursor:pointer}.load-more.svelte-1xl2tfr button:where(.svelte-1xl2tfr):hover:not(:disabled){background-color:#1976d20a}.load-more.svelte-1xl2tfr button:where(.svelte-1xl2tfr):disabled{opacity:.5;cursor:not-allowed}.spinning.svelte-1xl2tfr{animation:svelte-1xl2tfr-spin 1s linear infinite}@keyframes svelte-1xl2tfr-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}

View File

@@ -1 +1 @@
import{d as o,w as h}from"./B6rkT6DW.js";import{a as d}from"./DFI0ySgo.js";function g(){const{subscribe:t,set:s,update:l}=h({user:null,loading:!0,error:null});return{subscribe:t,async init(){l(r=>({...r,loading:!0,error:null}));try{const r=await d.getUser();s({user:r,loading:!1,error:null})}catch{s({user:null,loading:!1,error:null})}},logout(){d.logout()},clear(){s({user:null,loading:!1,error:null})}}}const f=g(),k=o(f,t=>t.user!==null),m=o(f,t=>t.user);function p(){const{subscribe:t,set:s,update:l}=h({status:null,loading:!1,error:null,lastUpdate:null});let r=null;return{subscribe:t,async refresh(){l(e=>({...e,loading:!0,error:null}));try{const e=await d.getStatus();s({status:e,loading:!1,error:null,lastUpdate:new Date})}catch(e){l(n=>({...n,loading:!1,error:e instanceof Error?e.message:"Failed to fetch status"}))}},startPolling(e=5e3){this.stopPolling(),this.refresh(),r=setInterval(()=>this.refresh(),e)},stopPolling(){r&&(clearInterval(r),r=null)},updateFromEvent(e){l(n=>{if(!n.status)return n;const a={...n.status};switch(e.type){case"agent.started":{const c=e.data;a.pool={...a.pool,active_count:a.pool.active_count+1,active_tasks:[...a.pool.active_tasks,c]};break}case"agent.completed":case"agent.killed":{const{task_id:c}=e.data;a.pool={...a.pool,active_count:Math.max(0,a.pool.active_count-1),active_tasks:a.pool.active_tasks.filter(i=>i.task_id!==c)};break}case"health.changed":{const{service:c,healthy:i}=e.data;a.health={...a.health,[c]:i};break}}return{...n,status:a,lastUpdate:new Date}})}}}const u=p(),w=o(u,t=>t.status?.health??null),y=o(u,t=>t.status?.pool??null),S=o(u,t=>t.status?.pool.active_tasks??[]),U=o(u,t=>t.status?.issue_counts??{});function v(){const{subscribe:t,set:s}=h({connected:!1,reconnecting:!1,error:null});return{subscribe:t,connect(){s({connected:!0,reconnecting:!1,error:null})},disconnect(){s({connected:!1,reconnecting:!1,error:null})},reconnect(){s({connected:!0,reconnecting:!1,error:null})}}}const A=v();export{S as a,k as b,f as c,u as d,A as e,m as f,w as h,U as i,y as p};
import{d as o,w as h}from"./B6rkT6DW.js";import{a as d}from"./tPs02WzX.js";function g(){const{subscribe:t,set:s,update:l}=h({user:null,loading:!0,error:null});return{subscribe:t,async init(){l(r=>({...r,loading:!0,error:null}));try{const r=await d.getUser();s({user:r,loading:!1,error:null})}catch{s({user:null,loading:!1,error:null})}},logout(){d.logout()},clear(){s({user:null,loading:!1,error:null})}}}const f=g(),k=o(f,t=>t.user!==null),m=o(f,t=>t.user);function p(){const{subscribe:t,set:s,update:l}=h({status:null,loading:!1,error:null,lastUpdate:null});let r=null;return{subscribe:t,async refresh(){l(e=>({...e,loading:!0,error:null}));try{const e=await d.getStatus();s({status:e,loading:!1,error:null,lastUpdate:new Date})}catch(e){l(n=>({...n,loading:!1,error:e instanceof Error?e.message:"Failed to fetch status"}))}},startPolling(e=5e3){this.stopPolling(),this.refresh(),r=setInterval(()=>this.refresh(),e)},stopPolling(){r&&(clearInterval(r),r=null)},updateFromEvent(e){l(n=>{if(!n.status)return n;const a={...n.status};switch(e.type){case"agent.started":{const c=e.data;a.pool={...a.pool,active_count:a.pool.active_count+1,active_tasks:[...a.pool.active_tasks,c]};break}case"agent.completed":case"agent.killed":{const{task_id:c}=e.data;a.pool={...a.pool,active_count:Math.max(0,a.pool.active_count-1),active_tasks:a.pool.active_tasks.filter(i=>i.task_id!==c)};break}case"health.changed":{const{service:c,healthy:i}=e.data;a.health={...a.health,[c]:i};break}}return{...n,status:a,lastUpdate:new Date}})}}}const u=p(),w=o(u,t=>t.status?.health??null),y=o(u,t=>t.status?.pool??null),S=o(u,t=>t.status?.pool.active_tasks??[]),U=o(u,t=>t.status?.issue_counts??{});function v(){const{subscribe:t,set:s}=h({connected:!1,reconnecting:!1,error:null});return{subscribe:t,connect(){s({connected:!0,reconnecting:!1,error:null})},disconnect(){s({connected:!1,reconnecting:!1,error:null})},reconnect(){s({connected:!0,reconnecting:!1,error:null})}}}const A=v();export{S as a,k as b,f as c,u as d,A as e,m as f,w as h,U as i,y as p};

View File

@@ -1 +1 @@
import{s as e}from"./CoqDomxY.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p};
import{s as e}from"./COMUFPmS.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{l as o,a as r}from"../chunks/CoqDomxY.js";export{o as load_css,r as start};

View File

@@ -0,0 +1 @@
import{l as o,a as r}from"../chunks/COMUFPmS.js";export{o as load_css,r as start};

View File

@@ -1 +1 @@
import{d as va,c as T,a as o,f as l,s as B}from"../chunks/BceKLUwb.js";import{o as pa,a as ha}from"../chunks/CazocS2O.js";import{V as da,X as ua,k as fa,f as ma,g as q,I as C,o as _a,s as ga,F as ba,v as s,w as p,x as a,y as D}from"../chunks/BkBQXocs.js";import{B as ya,i as _}from"../chunks/CwYE-Vvv.js";import{e as qa,s as E,i as xa}from"../chunks/DFI0ySgo.js";import{s as Aa}from"../chunks/DrK6eoHo.js";import{a as x,s as wa}from"../chunks/3ClrRLLp.js";import{p as ka}from"../chunks/B8sGlZxh.js";import{d as F,e as $,b as Pa,c as I,f as Ra}from"../chunks/BDiLOXX0.js";function Sa(z,A,...w){var k=new ya(z);da(()=>{const g=A()??null;k.ensure(g,g&&(P=>g(P,...w)))},ua)}const $a=!1,za=!0,Ja=Object.freeze(Object.defineProperty({__proto__:null,prerender:za,ssr:$a},Symbol.toStringTag,{value:"Module"}));var La=l('<div class="login-container"><div class="loading-container"><span class="material-icons" style="font-size: 48px; color: var(--mdc-theme-primary);">hourglass_empty</span> <p>Loading...</p></div></div>'),Ta=l('<div class="login-container"><div class="login-card svelte-12qhfyh"><span class="material-icons" style="font-size: 64px; color: var(--mdc-theme-primary); margin-bottom: 16px;">smart_toy</span> <h1 style="margin-bottom: 8px;">Agent Runner</h1> <p style="color: rgba(0,0,0,0.6); margin-bottom: 24px;">Sign in with Gitea to access the dashboard</p> <button class="login-button svelte-12qhfyh"><span class="material-icons">login</span> Sign in with Gitea</button></div></div>'),Ba=l('<span class="connection-status connected svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_done</span> Connected</span>'),Ca=l('<span class="connection-status reconnecting svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_sync</span> Reconnecting...</span>'),Da=l('<span class="connection-status disconnected svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_off</span> Disconnected</span>'),Ea=l('<img class="avatar svelte-12qhfyh"/>'),Fa=l('<div class="user-info svelte-12qhfyh"><!> <span> </span></div>'),Ia=l('<li><a><span class="material-icons svelte-12qhfyh"> </span> <span> </span></a></li>'),Ma=l('<div class="app-container"><header class="top-bar svelte-12qhfyh"><div class="top-bar-left svelte-12qhfyh"><span class="material-icons">smart_toy</span> <span class="app-title svelte-12qhfyh">Agent Runner</span></div> <div class="top-bar-right svelte-12qhfyh"><!> <!> <button class="icon-button svelte-12qhfyh" title="Logout"><span class="material-icons">logout</span></button></div></header> <div class="main-content"><nav class="sidebar svelte-12qhfyh"><ul class="nav-list svelte-12qhfyh"></ul></nav> <main class="page-content"><!></main></div></div>');function Ka(z,A){fa(A,!0);const w=()=>x(Pa,"$isAuthenticated",y),k=()=>x(ka,"$page",y),g=()=>x(I,"$auth",y),P=()=>x($,"$events",y),b=()=>x(Ra,"$currentUser",y),[y,W]=wa(),X=[{path:"/",label:"Dashboard",icon:"dashboard"},{path:"/agents",label:"Agents",icon:"smart_toy"},{path:"/issues",label:"Issues",icon:"assignment"},{path:"/builds",label:"Builds",icon:"build"},{path:"/config",label:"Config",icon:"settings"}];let M=ba(!1);pa(async()=>{await I.init(),ga(M,!0)}),ma(()=>{q(M)&&w()?(F.startPolling(5e3),$.connect()):(F.stopPolling(),$.disconnect())}),ha(()=>{F.stopPolling(),$.disconnect()});function H(){window.location.href="/oauth/login"}function J(){I.logout()}function K(r){return r==="/"?k().url.pathname==="/":k().url.pathname.startsWith(r)}var U=T(),Q=C(U);{var Y=r=>{var R=La();o(r,R)},Z=r=>{var R=T(),aa=C(R);{var sa=u=>{var h=Ta(),f=s(h),S=p(s(f),6);S.__click=H,a(f),a(h),o(u,h)},ta=u=>{var h=Ma(),f=s(h),S=p(s(f),2),j=s(S);{var ea=e=>{var t=Ba();o(e,t)},na=e=>{var t=T(),c=C(t);{var v=n=>{var i=Ca();o(n,i)},d=n=>{var i=Da();o(n,i)};_(c,n=>{P().reconnecting?n(v):n(d,!1)},!0)}o(e,t)};_(j,e=>{P().connected?e(ea):e(na,!1)})}var G=p(j,2);{var oa=e=>{var t=Fa(),c=s(t);{var v=i=>{var m=Ea();D(()=>{E(m,"src",b().avatar_url),E(m,"alt",b().username)}),o(i,m)};_(c,i=>{b().avatar_url&&i(v)})}var d=p(c,2),n=s(d,!0);a(d),a(t),D(()=>B(n,b().username)),o(e,t)};_(G,e=>{b()&&e(oa)})}var ra=p(G,2);ra.__click=J,a(S),a(f);var N=p(f,2),L=s(N),O=s(L);qa(O,21,()=>X,xa,(e,t)=>{var c=Ia(),v=s(c);let d;var n=s(v),i=s(n,!0);a(n);var m=p(n,2),la=s(m,!0);a(m),a(v),a(c),D(ca=>{E(v,"href",q(t).path),d=Aa(v,1,"nav-item svelte-12qhfyh",null,d,ca),B(i,q(t).icon),B(la,q(t).label)},[()=>({active:K(q(t).path)})]),o(e,c)}),a(O),a(L);var V=p(L,2),ia=s(V);Sa(ia,()=>A.children),a(V),a(N),a(h),o(u,h)};_(aa,u=>{w()?u(ta,!1):u(sa)},!0)}o(r,R)};_(Q,r=>{g().loading?r(Y):r(Z,!1)})}o(z,U),_a(),W()}va(["click"]);export{Ka as component,Ja as universal};
import{d as va,c as T,a as o,f as l,s as B}from"../chunks/BceKLUwb.js";import{o as pa,a as ha}from"../chunks/CazocS2O.js";import{V as da,X as ua,k as fa,f as ma,g as q,I as C,o as _a,s as ga,F as ya,v as s,w as p,x as a,y as D}from"../chunks/BkBQXocs.js";import{B as ba,i as _}from"../chunks/CwYE-Vvv.js";import{e as qa,s as E,i as xa}from"../chunks/tPs02WzX.js";import{s as Aa}from"../chunks/DrK6eoHo.js";import{a as x,s as wa}from"../chunks/3ClrRLLp.js";import{p as ka}from"../chunks/BhICUIF-.js";import{d as F,e as $,b as Pa,c as I,f as Ra}from"../chunks/BeWNdPuf.js";function Sa(z,A,...w){var k=new ba(z);da(()=>{const g=A()??null;k.ensure(g,g&&(P=>g(P,...w)))},ua)}const $a=!1,za=!0,Ja=Object.freeze(Object.defineProperty({__proto__:null,prerender:za,ssr:$a},Symbol.toStringTag,{value:"Module"}));var La=l('<div class="login-container"><div class="loading-container"><span class="material-icons" style="font-size: 48px; color: var(--mdc-theme-primary);">hourglass_empty</span> <p>Loading...</p></div></div>'),Ta=l('<div class="login-container"><div class="login-card svelte-12qhfyh"><span class="material-icons" style="font-size: 64px; color: var(--mdc-theme-primary); margin-bottom: 16px;">smart_toy</span> <h1 style="margin-bottom: 8px;">Agent Runner</h1> <p style="color: rgba(0,0,0,0.6); margin-bottom: 24px;">Sign in with Gitea to access the dashboard</p> <button class="login-button svelte-12qhfyh"><span class="material-icons">login</span> Sign in with Gitea</button></div></div>'),Ba=l('<span class="connection-status connected svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_done</span> Connected</span>'),Ca=l('<span class="connection-status reconnecting svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_sync</span> Reconnecting...</span>'),Da=l('<span class="connection-status disconnected svelte-12qhfyh"><span class="material-icons svelte-12qhfyh">cloud_off</span> Disconnected</span>'),Ea=l('<img class="avatar svelte-12qhfyh"/>'),Fa=l('<div class="user-info svelte-12qhfyh"><!> <span> </span></div>'),Ia=l('<li><a><span class="material-icons svelte-12qhfyh"> </span> <span> </span></a></li>'),Ma=l('<div class="app-container"><header class="top-bar svelte-12qhfyh"><div class="top-bar-left svelte-12qhfyh"><span class="material-icons">smart_toy</span> <span class="app-title svelte-12qhfyh">Agent Runner</span></div> <div class="top-bar-right svelte-12qhfyh"><!> <!> <button class="icon-button svelte-12qhfyh" title="Logout"><span class="material-icons">logout</span></button></div></header> <div class="main-content"><nav class="sidebar svelte-12qhfyh"><ul class="nav-list svelte-12qhfyh"></ul></nav> <main class="page-content"><!></main></div></div>');function Ka(z,A){fa(A,!0);const w=()=>x(Pa,"$isAuthenticated",b),k=()=>x(ka,"$page",b),g=()=>x(I,"$auth",b),P=()=>x($,"$events",b),y=()=>x(Ra,"$currentUser",b),[b,V]=wa(),W=[{path:"/",label:"Dashboard",icon:"dashboard"},{path:"/agents",label:"Agents",icon:"smart_toy"},{path:"/history",label:"History",icon:"history"},{path:"/issues",label:"Issues",icon:"assignment"},{path:"/builds",label:"Builds",icon:"build"},{path:"/config",label:"Config",icon:"settings"}];let M=ya(!1);pa(async()=>{await I.init(),ga(M,!0)}),ma(()=>{q(M)&&w()?(F.startPolling(5e3),$.connect()):(F.stopPolling(),$.disconnect())}),ha(()=>{F.stopPolling(),$.disconnect()});function X(){window.location.href="/oauth/login"}function J(){I.logout()}function K(r){return r==="/"?k().url.pathname==="/":k().url.pathname.startsWith(r)}var U=T(),Q=C(U);{var Y=r=>{var R=La();o(r,R)},Z=r=>{var R=T(),aa=C(R);{var sa=u=>{var h=Ta(),f=s(h),S=p(s(f),6);S.__click=X,a(f),a(h),o(u,h)},ta=u=>{var h=Ma(),f=s(h),S=p(s(f),2),j=s(S);{var ea=e=>{var t=Ba();o(e,t)},na=e=>{var t=T(),c=C(t);{var v=n=>{var i=Ca();o(n,i)},d=n=>{var i=Da();o(n,i)};_(c,n=>{P().reconnecting?n(v):n(d,!1)},!0)}o(e,t)};_(j,e=>{P().connected?e(ea):e(na,!1)})}var G=p(j,2);{var oa=e=>{var t=Fa(),c=s(t);{var v=i=>{var m=Ea();D(()=>{E(m,"src",y().avatar_url),E(m,"alt",y().username)}),o(i,m)};_(c,i=>{y().avatar_url&&i(v)})}var d=p(c,2),n=s(d,!0);a(d),a(t),D(()=>B(n,y().username)),o(e,t)};_(G,e=>{y()&&e(oa)})}var ra=p(G,2);ra.__click=J,a(S),a(f);var N=p(f,2),L=s(N),O=s(L);qa(O,21,()=>W,xa,(e,t)=>{var c=Ia(),v=s(c);let d;var n=s(v),i=s(n,!0);a(n);var m=p(n,2),la=s(m,!0);a(m),a(v),a(c),D(ca=>{E(v,"href",q(t).path),d=Aa(v,1,"nav-item svelte-12qhfyh",null,d,ca),B(i,q(t).icon),B(la,q(t).label)},[()=>({active:K(q(t).path)})]),o(e,c)}),a(O),a(L);var H=p(L,2),ia=s(H);Sa(ia,()=>A.children),a(H),a(N),a(h),o(u,h)};_(aa,u=>{w()?u(ta,!1):u(sa)},!0)}o(r,R)};_(Q,r=>{g().loading?r(Y):r(Z,!1)})}o(z,U),_a(),V()}va(["click"]);export{Ka as component,Ja as universal};

View File

@@ -1 +1 @@
import{f as u,a as h,s as a}from"../chunks/BceKLUwb.js";import{i as g}from"../chunks/ZR0UvfkB.js";import{k as v,I as l,y as d,o as x,v as e,x as o,w as _}from"../chunks/BkBQXocs.js";import{s as k,p}from"../chunks/CoqDomxY.js";const $={get error(){return p.error},get status(){return p.status}};k.updated.check;const m=$;var b=u("<h1> </h1> <p> </p>",1);function j(i,f){v(f,!1),g();var t=b(),r=l(t),n=e(r,!0);o(r);var s=_(r,2),c=e(s,!0);o(s),d(()=>{a(n,m.status),a(c,m.error?.message)}),h(i,t),x()}export{j as component};
import{f as u,a as h,s as a}from"../chunks/BceKLUwb.js";import{i as g}from"../chunks/ZR0UvfkB.js";import{k as v,I as l,y as d,o as x,v as e,x as o,w as _}from"../chunks/BkBQXocs.js";import{s as k,p}from"../chunks/COMUFPmS.js";const $={get error(){return p.error},get status(){return p.status}};k.updated.check;const m=$;var b=u("<h1> </h1> <p> </p>",1);function j(i,f){v(f,!1),g();var t=b(),r=l(t),n=e(r,!0);o(r);var s=_(r,2),c=e(s,!0);o(s),d(()=>{a(n,m.status),a(c,m.error?.message)}),h(i,t),x()}export{j as component};

View File

@@ -1 +1 @@
import{d as X,f as c,a as i,s as l}from"../chunks/BceKLUwb.js";import{i as Y}from"../chunks/ZR0UvfkB.js";import{k as Z,o as ss,v as e,w as n,x as t,y as S,g as o}from"../chunks/BkBQXocs.js";import{i as T}from"../chunks/CwYE-Vvv.js";import{e as as,s as es,i as ts,a as rs}from"../chunks/DFI0ySgo.js";import{s as E}from"../chunks/DrK6eoHo.js";import{s as os,a as M}from"../chunks/3ClrRLLp.js";import{p as ns,a as ls,d as ps}from"../chunks/BDiLOXX0.js";var is=c('<span class="pool-status svelte-h3sa6j"> </span>'),cs=c('<div class="empty-state svelte-h3sa6j"><span class="material-icons svelte-h3sa6j">smart_toy</span> <h2 class="svelte-h3sa6j">No Active Agents</h2> <p class="svelte-h3sa6j">Agents will appear here when processing issues</p></div>'),vs=c('<div class="table-row svelte-h3sa6j"><span class="col-issue svelte-h3sa6j"><a target="_blank" rel="noopener" class="svelte-h3sa6j"> </a></span> <span class="col-type"><span> </span></span> <span class="col-repo"> </span> <span class="col-started"> </span> <span class="col-elapsed"><span> </span></span> <span class="col-actions"><button class="action-button danger svelte-h3sa6j" title="Terminate agent"><span class="material-icons svelte-h3sa6j">stop</span></button></span></div>'),ds=c('<div class="agent-table svelte-h3sa6j"><div class="table-header svelte-h3sa6j"><span class="col-issue">Issue</span> <span class="col-type">Type</span> <span class="col-repo">Repository</span> <span class="col-started">Started</span> <span class="col-elapsed">Elapsed</span> <span class="col-actions">Actions</span></div> <!></div>'),_s=c('<div class="agents-page svelte-h3sa6j"><div class="page-header svelte-h3sa6j"><h1 class="page-title svelte-h3sa6j">Agents</h1> <!></div> <!></div>');function $s(D,F){Z(F,!1);const v=()=>M(ns,"$pool",x),k=()=>M(ls,"$activeAgents",x),[x,I]=os();function K(s){const a=Math.floor(s/60),p=Math.floor(s%60);return`${a}:${p.toString().padStart(2,"0")}`}function L(s){return new Date(s).toLocaleTimeString()}async function N(s){if(confirm("Are you sure you want to terminate this agent?"))try{await rs.killAgent(s,"manual"),ps.refresh()}catch(a){alert("Failed to terminate agent: "+(a instanceof Error?a.message:"Unknown error"))}}Y();var d=_s(),_=e(d),R=n(e(_),2);{var U=s=>{var a=is(),p=e(a);t(a),S(()=>l(p,`${v().active_count??""} / ${v().max_agents??""} active`)),i(s,a)};T(R,s=>{v()&&s(U)})}t(_);var q=n(_,2);{var z=s=>{var a=cs();i(s,a)},B=s=>{var a=ds(),p=n(e(a),2);as(p,1,k,ts,(C,r)=>{var h=vs(),m=e(h),u=e(m),G=e(u,!0);t(u),t(m);var f=n(m,2),g=e(f),H=e(g,!0);t(g),t(f);var j=n(f,2),J=e(j,!0);t(j);var b=n(j,2),O=e(b,!0);t(b);var y=n(b,2),$=e(y);let A;var P=e($,!0);t($),t(y);var w=n(y,2),Q=e(w);Q.__click=()=>N(o(r).task_id),t(w),t(h),S((V,W)=>{es(u,"href",`https://track.cleargrow.io/issue/${o(r).issue_id??""}`),l(G,o(r).issue_id),E(g,1,`type-badge ${o(r).task_type??""}`,"svelte-h3sa6j"),l(H,o(r).task_type),l(J,o(r).repo),l(O,V),A=E($,1,"elapsed-badge svelte-h3sa6j",null,A,{warning:o(r).elapsed_seconds>900,danger:o(r).elapsed_seconds>1500}),l(P,W)},[()=>L(o(r).start_time),()=>K(o(r).elapsed_seconds)]),i(C,h)}),t(a),i(s,a)};T(q,s=>{k().length===0?s(z):s(B,!1)})}t(d),i(D,d),ss(),I()}X(["click"]);export{$s as component};
import{d as X,f as c,a as i,s as l}from"../chunks/BceKLUwb.js";import{i as Y}from"../chunks/ZR0UvfkB.js";import{k as Z,o as ss,v as e,w as n,x as t,y as S,g as o}from"../chunks/BkBQXocs.js";import{i as T}from"../chunks/CwYE-Vvv.js";import{e as as,s as es,i as ts,a as rs}from"../chunks/tPs02WzX.js";import{s as E}from"../chunks/DrK6eoHo.js";import{s as os,a as M}from"../chunks/3ClrRLLp.js";import{p as ns,a as ls,d as ps}from"../chunks/BeWNdPuf.js";var is=c('<span class="pool-status svelte-h3sa6j"> </span>'),cs=c('<div class="empty-state svelte-h3sa6j"><span class="material-icons svelte-h3sa6j">smart_toy</span> <h2 class="svelte-h3sa6j">No Active Agents</h2> <p class="svelte-h3sa6j">Agents will appear here when processing issues</p></div>'),vs=c('<div class="table-row svelte-h3sa6j"><span class="col-issue svelte-h3sa6j"><a target="_blank" rel="noopener" class="svelte-h3sa6j"> </a></span> <span class="col-type"><span> </span></span> <span class="col-repo"> </span> <span class="col-started"> </span> <span class="col-elapsed"><span> </span></span> <span class="col-actions"><button class="action-button danger svelte-h3sa6j" title="Terminate agent"><span class="material-icons svelte-h3sa6j">stop</span></button></span></div>'),ds=c('<div class="agent-table svelte-h3sa6j"><div class="table-header svelte-h3sa6j"><span class="col-issue">Issue</span> <span class="col-type">Type</span> <span class="col-repo">Repository</span> <span class="col-started">Started</span> <span class="col-elapsed">Elapsed</span> <span class="col-actions">Actions</span></div> <!></div>'),_s=c('<div class="agents-page svelte-h3sa6j"><div class="page-header svelte-h3sa6j"><h1 class="page-title svelte-h3sa6j">Agents</h1> <!></div> <!></div>');function $s(D,F){Z(F,!1);const v=()=>M(ns,"$pool",x),k=()=>M(ls,"$activeAgents",x),[x,I]=os();function K(s){const a=Math.floor(s/60),p=Math.floor(s%60);return`${a}:${p.toString().padStart(2,"0")}`}function L(s){return new Date(s).toLocaleTimeString()}async function N(s){if(confirm("Are you sure you want to terminate this agent?"))try{await rs.killAgent(s,"manual"),ps.refresh()}catch(a){alert("Failed to terminate agent: "+(a instanceof Error?a.message:"Unknown error"))}}Y();var d=_s(),_=e(d),R=n(e(_),2);{var U=s=>{var a=is(),p=e(a);t(a),S(()=>l(p,`${v().active_count??""} / ${v().max_agents??""} active`)),i(s,a)};T(R,s=>{v()&&s(U)})}t(_);var q=n(_,2);{var z=s=>{var a=cs();i(s,a)},B=s=>{var a=ds(),p=n(e(a),2);as(p,1,k,ts,(C,r)=>{var h=vs(),m=e(h),u=e(m),G=e(u,!0);t(u),t(m);var f=n(m,2),g=e(f),H=e(g,!0);t(g),t(f);var j=n(f,2),J=e(j,!0);t(j);var b=n(j,2),O=e(b,!0);t(b);var y=n(b,2),$=e(y);let A;var P=e($,!0);t($),t(y);var w=n(y,2),Q=e(w);Q.__click=()=>N(o(r).task_id),t(w),t(h),S((V,W)=>{es(u,"href",`https://track.cleargrow.io/issue/${o(r).issue_id??""}`),l(G,o(r).issue_id),E(g,1,`type-badge ${o(r).task_type??""}`,"svelte-h3sa6j"),l(H,o(r).task_type),l(J,o(r).repo),l(O,V),A=E($,1,"elapsed-badge svelte-h3sa6j",null,A,{warning:o(r).elapsed_seconds>900,danger:o(r).elapsed_seconds>1500}),l(P,W)},[()=>L(o(r).start_time),()=>K(o(r).elapsed_seconds)]),i(C,h)}),t(a),i(s,a)};T(q,s=>{k().length===0?s(z):s(B,!1)})}t(d),i(D,d),ss(),I()}X(["click"]);export{$s as component};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{d as wa,f as u,a as i,s as c,c as V}from"../chunks/BceKLUwb.js";import{o as Ba}from"../chunks/CazocS2O.js";import{k as Sa,F as D,G as Da,o as Fa,s as m,g as a,w as o,v as e,x as t,y as K,I as W}from"../chunks/BkBQXocs.js";import{i as F}from"../chunks/CwYE-Vvv.js";import{e as X,a as Y,i as Z,s as $}from"../chunks/DFI0ySgo.js";import{s as M}from"../chunks/DrK6eoHo.js";var Ma=u("<button> </button>"),Ra=u('<div class="loading-state svelte-1itx8h6"><span class="material-icons spinning svelte-1itx8h6">sync</span> <p>Loading builds...</p></div>'),Aa=u('<div class="error-state svelte-1itx8h6"><span class="material-icons svelte-1itx8h6">error</span> <p> </p> <button class="svelte-1itx8h6">Retry</button></div>'),Ea=u('<div class="empty-state svelte-1itx8h6"><span class="material-icons svelte-1itx8h6">build</span> <h2>No Builds Found</h2> <p>No builds match the selected filter</p></div>'),Ia=u('<button class="action-button svelte-1itx8h6" title="Retry build"><span class="material-icons svelte-1itx8h6">replay</span></button>'),La=u('<div><span class="col-status"><span><span> </span></span></span> <span class="col-number svelte-1itx8h6"><a target="_blank" rel="noopener" class="svelte-1itx8h6"> </a></span> <span class="col-branch"><span class="branch-badge svelte-1itx8h6"> </span></span> <span class="col-message svelte-1itx8h6"> </span> <span class="col-author"> </span> <span class="col-duration svelte-1itx8h6"> </span> <span class="col-time svelte-1itx8h6"> </span> <span class="col-actions"><!></span></div>'),Na=u('<div class="builds-table svelte-1itx8h6"><div class="table-header svelte-1itx8h6"><span class="col-status">Status</span> <span class="col-number">#</span> <span class="col-branch">Branch</span> <span class="col-message svelte-1itx8h6">Message</span> <span class="col-author">Author</span> <span class="col-duration svelte-1itx8h6">Duration</span> <span class="col-time svelte-1itx8h6">Started</span> <span class="col-actions">Actions</span></div> <!></div>'),Ga=u('<div class="builds-page svelte-1itx8h6"><h1 class="page-title svelte-1itx8h6">Builds</h1> <div class="repo-filter svelte-1itx8h6"></div> <!></div>');function Ha(aa,sa){Sa(sa,!0);let R=D(Da([])),A=D(!0),y=D(null),v=D("all");const ta=["all","controller","probe","docs"];Ba(()=>{k()});async function k(){m(A,!0),m(y,null);try{const s=a(v)==="all"?void 0:a(v);m(R,await Y.getBuilds(s),!0)}catch(s){m(y,s instanceof Error?s.message:"Failed to load builds",!0)}finally{m(A,!1)}}async function ea(s,n){try{await Y.retryBuild(s,n),k()}catch(l){alert("Failed to retry build: "+(l instanceof Error?l.message:"Unknown error"))}}function ra(s,n){if(!s)return"-";const l=n||Date.now()/1e3,h=Math.floor(l-s),f=Math.floor(h/60),p=h%60;return`${f}:${p.toString().padStart(2,"0")}`}function na(s){return new Date(s*1e3).toLocaleString()}function la(s){return{success:"check_circle",failure:"cancel",running:"sync",pending:"schedule",killed:"block"}[s]||"help"}var E=Ga(),I=o(e(E),2);X(I,21,()=>ta,Z,(s,n)=>{var l=Ma();let h;l.__click=()=>{m(v,a(n),!0),k()};var f=e(l,!0);t(l),K(()=>{h=M(l,1,"repo-tab svelte-1itx8h6",null,h,{active:a(v)===a(n)}),c(f,a(n)==="all"?"All":a(n))}),i(s,l)}),t(I);var oa=o(I,2);{var ia=s=>{var n=Ra();i(s,n)},ca=s=>{var n=V(),l=W(n);{var h=p=>{var d=Aa(),x=o(e(d),2),L=e(x,!0);t(x);var N=o(x,2);N.__click=k,t(d),K(()=>c(L,a(y))),i(p,d)},f=p=>{var d=V(),x=W(d);{var L=_=>{var g=Ea();i(_,g)},N=_=>{var g=Na(),va=o(e(g),2);X(va,17,()=>a(R),Z,(pa,r)=>{var w=La(),G=e(w),T=e(G),U=e(T);let O;var ua=e(U,!0);t(U),t(T),t(G);var j=o(G,2),q=e(j),ha=e(q,!0);t(q),t(j);var z=o(j,2),P=e(z),da=e(P,!0);t(P),t(z);var B=o(z,2),_a=e(B,!0);t(B);var C=o(B,2),ma=e(C,!0);t(C);var H=o(C,2),fa=e(H,!0);t(H);var J=o(H,2),xa=e(J,!0);t(J);var Q=o(J,2),ga=e(Q);{var ba=b=>{var S=Ia();S.__click=()=>ea(a(v)==="all"?"controller":a(v),a(r).number),i(b,S)};F(ga,b=>{a(r).status==="failure"&&b(ba)})}t(Q),t(w),K((b,S,ya,ka)=>{M(w,1,`table-row status-${a(r).status??""}`,"svelte-1itx8h6"),M(T,1,`status-icon status-${a(r).status??""}`,"svelte-1itx8h6"),O=M(U,1,"material-icons svelte-1itx8h6",null,O,{spinning:a(r).status==="running"}),c(ua,b),$(q,"href",`https://ci.cleargrow.io/repos/cleargrow/${(a(v)==="all"?"controller":a(v))??""}/pipeline/${a(r).number??""}`),c(ha,a(r).number),c(da,a(r).branch),$(B,"title",a(r).message),c(_a,S),c(ma,a(r).author),c(fa,ya),c(xa,ka)},[()=>la(a(r).status),()=>a(r).message.length>50?a(r).message.slice(0,50)+"...":a(r).message,()=>ra(a(r).started,a(r).finished),()=>na(a(r).created)]),i(pa,w)}),t(g),i(_,g)};F(x,_=>{a(R).length===0?_(L):_(N,!1)},!0)}i(p,d)};F(l,p=>{a(y)?p(h):p(f,!1)},!0)}i(s,n)};F(oa,s=>{a(A)?s(ia):s(ca,!1)})}t(E),i(aa,E),Fa()}wa(["click"]);export{Ha as component};
import{d as wa,f as u,a as i,s as c,c as V}from"../chunks/BceKLUwb.js";import{o as Ba}from"../chunks/CazocS2O.js";import{k as Sa,F as D,G as Da,o as Fa,s as m,g as a,w as o,v as e,x as t,y as K,I as W}from"../chunks/BkBQXocs.js";import{i as F}from"../chunks/CwYE-Vvv.js";import{e as X,a as Y,i as Z,s as $}from"../chunks/tPs02WzX.js";import{s as M}from"../chunks/DrK6eoHo.js";var Ma=u("<button> </button>"),Ra=u('<div class="loading-state svelte-1itx8h6"><span class="material-icons spinning svelte-1itx8h6">sync</span> <p>Loading builds...</p></div>'),Aa=u('<div class="error-state svelte-1itx8h6"><span class="material-icons svelte-1itx8h6">error</span> <p> </p> <button class="svelte-1itx8h6">Retry</button></div>'),Ea=u('<div class="empty-state svelte-1itx8h6"><span class="material-icons svelte-1itx8h6">build</span> <h2>No Builds Found</h2> <p>No builds match the selected filter</p></div>'),Ia=u('<button class="action-button svelte-1itx8h6" title="Retry build"><span class="material-icons svelte-1itx8h6">replay</span></button>'),La=u('<div><span class="col-status"><span><span> </span></span></span> <span class="col-number svelte-1itx8h6"><a target="_blank" rel="noopener" class="svelte-1itx8h6"> </a></span> <span class="col-branch"><span class="branch-badge svelte-1itx8h6"> </span></span> <span class="col-message svelte-1itx8h6"> </span> <span class="col-author"> </span> <span class="col-duration svelte-1itx8h6"> </span> <span class="col-time svelte-1itx8h6"> </span> <span class="col-actions"><!></span></div>'),Na=u('<div class="builds-table svelte-1itx8h6"><div class="table-header svelte-1itx8h6"><span class="col-status">Status</span> <span class="col-number">#</span> <span class="col-branch">Branch</span> <span class="col-message svelte-1itx8h6">Message</span> <span class="col-author">Author</span> <span class="col-duration svelte-1itx8h6">Duration</span> <span class="col-time svelte-1itx8h6">Started</span> <span class="col-actions">Actions</span></div> <!></div>'),Ga=u('<div class="builds-page svelte-1itx8h6"><h1 class="page-title svelte-1itx8h6">Builds</h1> <div class="repo-filter svelte-1itx8h6"></div> <!></div>');function Ha(aa,sa){Sa(sa,!0);let R=D(Da([])),A=D(!0),y=D(null),v=D("all");const ta=["all","controller","probe","docs"];Ba(()=>{k()});async function k(){m(A,!0),m(y,null);try{const s=a(v)==="all"?void 0:a(v);m(R,await Y.getBuilds(s),!0)}catch(s){m(y,s instanceof Error?s.message:"Failed to load builds",!0)}finally{m(A,!1)}}async function ea(s,n){try{await Y.retryBuild(s,n),k()}catch(l){alert("Failed to retry build: "+(l instanceof Error?l.message:"Unknown error"))}}function ra(s,n){if(!s)return"-";const l=n||Date.now()/1e3,h=Math.floor(l-s),f=Math.floor(h/60),p=h%60;return`${f}:${p.toString().padStart(2,"0")}`}function na(s){return new Date(s*1e3).toLocaleString()}function la(s){return{success:"check_circle",failure:"cancel",running:"sync",pending:"schedule",killed:"block"}[s]||"help"}var E=Ga(),I=o(e(E),2);X(I,21,()=>ta,Z,(s,n)=>{var l=Ma();let h;l.__click=()=>{m(v,a(n),!0),k()};var f=e(l,!0);t(l),K(()=>{h=M(l,1,"repo-tab svelte-1itx8h6",null,h,{active:a(v)===a(n)}),c(f,a(n)==="all"?"All":a(n))}),i(s,l)}),t(I);var oa=o(I,2);{var ia=s=>{var n=Ra();i(s,n)},ca=s=>{var n=V(),l=W(n);{var h=p=>{var d=Aa(),x=o(e(d),2),L=e(x,!0);t(x);var N=o(x,2);N.__click=k,t(d),K(()=>c(L,a(y))),i(p,d)},f=p=>{var d=V(),x=W(d);{var L=_=>{var g=Ea();i(_,g)},N=_=>{var g=Na(),va=o(e(g),2);X(va,17,()=>a(R),Z,(pa,r)=>{var w=La(),G=e(w),T=e(G),U=e(T);let O;var ua=e(U,!0);t(U),t(T),t(G);var j=o(G,2),q=e(j),ha=e(q,!0);t(q),t(j);var z=o(j,2),P=e(z),da=e(P,!0);t(P),t(z);var B=o(z,2),_a=e(B,!0);t(B);var C=o(B,2),ma=e(C,!0);t(C);var H=o(C,2),fa=e(H,!0);t(H);var J=o(H,2),xa=e(J,!0);t(J);var Q=o(J,2),ga=e(Q);{var ba=b=>{var S=Ia();S.__click=()=>ea(a(v)==="all"?"controller":a(v),a(r).number),i(b,S)};F(ga,b=>{a(r).status==="failure"&&b(ba)})}t(Q),t(w),K((b,S,ya,ka)=>{M(w,1,`table-row status-${a(r).status??""}`,"svelte-1itx8h6"),M(T,1,`status-icon status-${a(r).status??""}`,"svelte-1itx8h6"),O=M(U,1,"material-icons svelte-1itx8h6",null,O,{spinning:a(r).status==="running"}),c(ua,b),$(q,"href",`https://ci.cleargrow.io/repos/cleargrow/${(a(v)==="all"?"controller":a(v))??""}/pipeline/${a(r).number??""}`),c(ha,a(r).number),c(da,a(r).branch),$(B,"title",a(r).message),c(_a,S),c(ma,a(r).author),c(fa,ya),c(xa,ka)},[()=>la(a(r).status),()=>a(r).message.length>50?a(r).message.slice(0,50)+"...":a(r).message,()=>ra(a(r).started,a(r).finished),()=>na(a(r).created)]),i(pa,w)}),t(g),i(_,g)};F(x,_=>{a(R).length===0?_(L):_(N,!1)},!0)}i(p,d)};F(l,p=>{a(y)?p(h):p(f,!1)},!0)}i(s,n)};F(oa,s=>{a(A)?s(ia):s(ca,!1)})}t(E),i(aa,E),Fa()}wa(["click"]);export{Ha as component};

View File

@@ -0,0 +1 @@
import{d as kt,f as d,a as o,c as X,s as f,t as wt}from"../chunks/BceKLUwb.js";import{o as Mt}from"../chunks/CazocS2O.js";import{k as Dt,F as M,G as Ht,w as r,y as A,o as Tt,s as c,g as t,v as a,J as Ft,x as e,I as B}from"../chunks/BkBQXocs.js";import{i as D}from"../chunks/CwYE-Vvv.js";import{a as Lt,e as St,s as At,i as Rt}from"../chunks/tPs02WzX.js";import{s as Z}from"../chunks/DrK6eoHo.js";var $t=d('<div class="loading svelte-1xl2tfr"><span class="material-icons spinning svelte-1xl2tfr">sync</span> <p>Loading history...</p></div>'),Ct=d('<div class="error-state svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">error</span> <p> </p> <button class="svelte-1xl2tfr">Retry</button></div>'),Et=d('<div class="empty-state svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">history</span> <h2>No History Yet</h2> <p>Agent runs will appear here once completed</p></div>'),Gt=d('<a class="history-card svelte-1xl2tfr"><div class="card-header svelte-1xl2tfr"><span class="issue-id svelte-1xl2tfr"> </span> <span> </span></div> <div class="card-body svelte-1xl2tfr"><div class="meta-row svelte-1xl2tfr"><span class="task-type svelte-1xl2tfr"> </span> <span class="repo svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">folder</span> </span></div> <div class="meta-row svelte-1xl2tfr"><span class="time svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">schedule</span> </span> <span class="duration svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">timer</span> </span></div> <div class="message-count svelte-1xl2tfr"><span class="material-icons svelte-1xl2tfr">chat</span> </div></div></a>'),It=d('<span class="material-icons spinning svelte-1xl2tfr">sync</span>'),Jt=d('<div class="load-more svelte-1xl2tfr"><button class="svelte-1xl2tfr"><!></button></div>'),Nt=d('<div class="history-list svelte-1xl2tfr"></div> <!>',1),Yt=d('<div class="history-page svelte-1xl2tfr"><div class="header svelte-1xl2tfr"><h1 class="svelte-1xl2tfr">Agent History</h1> <button class="refresh-button svelte-1xl2tfr"><span>refresh</span> Refresh</button></div> <!></div>');function Pt(tt,st){Dt(st,!0);let p=M(Ht([])),_=M(!0),H=M(null),K=M(!0),R=M(0);const O=25;Mt(()=>{T()});async function T(s=!1){s||(c(_,!0),c(R,0)),c(H,null);try{const l=await Lt.getHistory(O,s?t(R):0);s?c(p,[...t(p),...l.runs],!0):c(p,l.runs,!0),c(K,l.runs.length===O),c(R,t(p).length,!0)}catch(l){c(H,l instanceof Error?l.message:"Failed to load history",!0)}finally{c(_,!1)}}function et(){T(!0)}function at(s){return s?new Date(s).toLocaleString():"-"}function rt(s,l){if(!s||!l)return"-";const E=new Date(l).getTime()-new Date(s).getTime(),g=Math.floor(E/1e3),L=Math.floor(g/60);return L>0?`${L}m ${g%60}s`:`${g}s`}function lt(s){return s.timed_out?"timeout":s.returncode===0?"success":"error"}function it(s){return s.timed_out?"Timeout":s.returncode===0?"Success":`Failed (${s.returncode})`}var $=Yt(),C=a($),F=r(a(C),2);F.__click=()=>T();var ot=a(F);let P;Ft(),e(F),e(C);var nt=r(C,2);{var vt=s=>{var l=$t();o(s,l)},ct=s=>{var l=X(),E=B(l);{var g=u=>{var m=Ct(),h=r(a(m),2),G=a(h,!0);e(h);var I=r(h,2);I.__click=()=>T(),e(m),A(()=>f(G,t(H))),o(u,m)},L=u=>{var m=X(),h=B(m);{var G=x=>{var S=Et();o(x,S)},I=x=>{var S=Nt(),J=B(S);St(J,21,()=>t(p),Rt,(y,i)=>{var v=Gt(),b=a(v),k=a(b),N=a(k,!0);e(k);var n=r(k,2),w=a(n,!0);e(n),e(b);var Q=r(b,2),Y=a(Q),j=a(Y),pt=a(j,!0);e(j);var U=r(j,2),_t=r(a(U));e(U),e(Y);var q=r(Y,2),z=a(q),ut=r(a(z));e(z);var V=r(z,2),mt=r(a(V));e(V),e(q);var W=r(q,2),xt=r(a(W));e(W),e(Q),e(v),A((gt,ht,yt,bt)=>{At(v,"href",`/agents/${t(i).task_id??""}`),f(N,t(i).issue_id),Z(n,1,`status status-${gt??""}`,"svelte-1xl2tfr"),f(w,ht),f(pt,t(i).task_type),f(_t,` ${t(i).repo??""}`),f(ut,` ${yt??""}`),f(mt,` ${bt??""}`),f(xt,` ${t(i).message_count??""} messages`)},[()=>lt(t(i)),()=>it(t(i)),()=>at(t(i).started_at),()=>rt(t(i).started_at,t(i).completed_at)]),o(y,v)}),e(J);var ft=r(J,2);{var dt=y=>{var i=Jt(),v=a(i);v.__click=et;var b=a(v);{var k=n=>{var w=It();o(n,w)},N=n=>{var w=wt("Load More");o(n,w)};D(b,n=>{t(_)?n(k):n(N,!1)})}e(v),e(i),A(()=>v.disabled=t(_)),o(y,i)};D(ft,y=>{t(K)&&y(dt)})}o(x,S)};D(h,x=>{t(p).length===0?x(G):x(I,!1)},!0)}o(u,m)};D(E,u=>{t(H)?u(g):u(L,!1)},!0)}o(s,l)};D(nt,s=>{t(_)&&t(p).length===0?s(vt):s(ct,!1)})}e($),A(()=>{F.disabled=t(_),P=Z(ot,1,"material-icons svelte-1xl2tfr",null,P,{spinning:t(_)})}),o(tt,$),Tt()}kt(["click"]);export{Pt as component};

View File

@@ -1 +1 @@
import{d as wa,f as d,a as l,s as p,c as X}from"../chunks/BceKLUwb.js";import{o as ga}from"../chunks/CazocS2O.js";import{k as ha,F as D,G as ya,o as ba,w as o,s as u,g as a,v as t,x as e,y as m,I as Y,J as Ia}from"../chunks/BkBQXocs.js";import{i as y}from"../chunks/CwYE-Vvv.js";import{e as V,a as Z,i as j,s as $a}from"../chunks/DFI0ySgo.js";import{s as aa}from"../chunks/DrK6eoHo.js";import{s as Ra,a as Sa}from"../chunks/3ClrRLLp.js";import{p as Da}from"../chunks/B8sGlZxh.js";var Fa=d("<button> </button>"),La=d('<div class="loading-state svelte-1k9wk9x"><span class="material-icons spinning svelte-1k9wk9x">sync</span> <p>Loading issues...</p></div>'),Ca=d('<div class="error-state svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">error</span> <p> </p> <button class="svelte-1k9wk9x">Retry</button></div>'),Ea=d('<div class="empty-state svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">check_circle</span> <h2> </h2> <p>All issues have been processed or moved to another state</p></div>'),Ma=d('<span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">label</span> </span>'),Pa=d('<span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">flag</span> </span>'),Aa=d("<option> </option>"),Ba=d('<div class="issue-card svelte-1k9wk9x"><div class="issue-header svelte-1k9wk9x"><a target="_blank" rel="noopener" class="issue-id svelte-1k9wk9x"> </a> <span> </span></div> <h3 class="issue-summary svelte-1k9wk9x"> </h3> <div class="issue-meta svelte-1k9wk9x"><!> <!> <span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">schedule</span> </span></div> <div class="issue-actions svelte-1k9wk9x"><select class="svelte-1k9wk9x"><option>Move to...</option><!></select></div></div>'),Ga=d('<div class="issues-list svelte-1k9wk9x"></div>'),Ja=d('<div class="issues-page svelte-1k9wk9x"><h1 class="page-title svelte-1k9wk9x">Issue Queue</h1> <div class="state-tabs svelte-1k9wk9x"></div> <!></div>');function Ha(ea,sa){ha(sa,!0);const ta=()=>Sa(Da,"$page",ra),[ra,oa]=Ra();let F=D(ya([])),L=D(!0),b=D(null),g=D("Ready");const q=["Ready","In Progress","Build","Verify","Document","Review"];ga(()=>{const s=ta().url.searchParams.get("state");s&&u(g,s,!0),I()});async function I(){u(L,!0),u(b,null);try{u(F,await Z.getIssues([a(g)]),!0)}catch(s){u(b,s instanceof Error?s.message:"Failed to load issues",!0)}finally{u(L,!1)}}async function va(s,n){try{await Z.transitionIssue(s,n),I()}catch(c){alert("Failed to transition issue: "+(c instanceof Error?c.message:"Unknown error"))}}function ia(s){u(g,s,!0),I()}var C=Ja(),E=o(t(C),2);V(E,21,()=>q,j,(s,n)=>{var c=Fa();let $;c.__click=()=>ia(a(n));var M=t(c,!0);e(c),m(()=>{$=aa(c,1,"state-tab svelte-1k9wk9x",null,$,{active:a(g)===a(n)}),p(M,a(n))}),l(s,c)}),e(E);var la=o(E,2);{var na=s=>{var n=La();l(s,n)},ca=s=>{var n=X(),c=Y(n);{var $=x=>{var f=Ca(),h=o(t(f),2),P=t(h,!0);e(h);var A=o(h,2);A.__click=I,e(f),m(()=>p(P,a(b))),l(x,f)},M=x=>{var f=X(),h=Y(f);{var P=w=>{var k=Ea(),R=o(t(k),2),v=t(R);e(R),Ia(2),e(k),m(()=>p(v,`No Issues in ${a(g)??""}`)),l(w,k)},A=w=>{var k=Ga();V(k,21,()=>a(F),j,(R,v)=>{var B=Ba(),G=t(B),S=t(G),pa=t(S,!0);e(S);var J=o(S,2),da=t(J,!0);e(J),e(G);var N=o(G,2),_a=t(N,!0);e(N);var Q=o(N,2),z=t(Q);{var ka=r=>{var i=Ma(),_=o(t(i));e(i),m(()=>p(_,` ${a(v).type??""}`)),l(r,i)};y(z,r=>{a(v).type&&r(ka)})}var H=o(z,2);{var ua=r=>{var i=Pa(),_=o(t(i));e(i),m(()=>p(_,` ${a(v).priority??""}`)),l(r,i)};y(H,r=>{a(v).priority&&r(ua)})}var K=o(H,2),ma=o(t(K));e(K),e(Q);var O=o(Q,2),T=t(O);T.__change=r=>va(a(v).id,r.target.value);var U=t(T);U.value=U.__value="";var xa=o(U);V(xa,17,()=>q.filter(r=>r!==a(v).state),j,(r,i)=>{var _=Aa(),fa=t(_,!0);e(_);var W={};m(()=>{p(fa,a(i)),W!==(W=a(i))&&(_.value=(_.__value=a(i))??"")}),l(r,_)}),e(T),e(O),e(B),m((r,i)=>{$a(S,"href",`https://track.cleargrow.io/issue/${a(v).id??""}`),p(pa,a(v).id),aa(J,1,`issue-state state-${r??""}`,"svelte-1k9wk9x"),p(da,a(v).state),p(_a,a(v).summary),p(ma,` ${i??""}`)},[()=>a(v).state.toLowerCase().replace(" ","-"),()=>new Date(a(v).updated).toLocaleDateString()]),l(R,B)}),e(k),l(w,k)};y(h,w=>{a(F).length===0?w(P):w(A,!1)},!0)}l(x,f)};y(c,x=>{a(b)?x($):x(M,!1)},!0)}l(s,n)};y(la,s=>{a(L)?s(na):s(ca,!1)})}e(C),l(ea,C),ba(),oa()}wa(["click","change"]);export{Ha as component};
import{d as wa,f as d,a as l,s as p,c as X}from"../chunks/BceKLUwb.js";import{o as ga}from"../chunks/CazocS2O.js";import{k as ha,F as D,G as ya,o as ba,w as o,v as t,s as u,g as a,x as e,y as m,I as Y,J as Ia}from"../chunks/BkBQXocs.js";import{i as y}from"../chunks/CwYE-Vvv.js";import{e as V,a as Z,i as j,s as $a}from"../chunks/tPs02WzX.js";import{s as aa}from"../chunks/DrK6eoHo.js";import{s as Ra,a as Sa}from"../chunks/3ClrRLLp.js";import{p as Da}from"../chunks/BhICUIF-.js";var Fa=d("<button> </button>"),La=d('<div class="loading-state svelte-1k9wk9x"><span class="material-icons spinning svelte-1k9wk9x">sync</span> <p>Loading issues...</p></div>'),Ca=d('<div class="error-state svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">error</span> <p> </p> <button class="svelte-1k9wk9x">Retry</button></div>'),Ea=d('<div class="empty-state svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">check_circle</span> <h2> </h2> <p>All issues have been processed or moved to another state</p></div>'),Ma=d('<span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">label</span> </span>'),Pa=d('<span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">flag</span> </span>'),Aa=d("<option> </option>"),Ba=d('<div class="issue-card svelte-1k9wk9x"><div class="issue-header svelte-1k9wk9x"><a target="_blank" rel="noopener" class="issue-id svelte-1k9wk9x"> </a> <span> </span></div> <h3 class="issue-summary svelte-1k9wk9x"> </h3> <div class="issue-meta svelte-1k9wk9x"><!> <!> <span class="meta-item svelte-1k9wk9x"><span class="material-icons svelte-1k9wk9x">schedule</span> </span></div> <div class="issue-actions svelte-1k9wk9x"><select class="svelte-1k9wk9x"><option>Move to...</option><!></select></div></div>'),Ga=d('<div class="issues-list svelte-1k9wk9x"></div>'),Ja=d('<div class="issues-page svelte-1k9wk9x"><h1 class="page-title svelte-1k9wk9x">Issue Queue</h1> <div class="state-tabs svelte-1k9wk9x"></div> <!></div>');function Ha(ea,sa){ha(sa,!0);const ta=()=>Sa(Da,"$page",ra),[ra,oa]=Ra();let F=D(ya([])),L=D(!0),b=D(null),g=D("Ready");const q=["Ready","In Progress","Build","Verify","Document","Review"];ga(()=>{const s=ta().url.searchParams.get("state");s&&u(g,s,!0),I()});async function I(){u(L,!0),u(b,null);try{u(F,await Z.getIssues([a(g)]),!0)}catch(s){u(b,s instanceof Error?s.message:"Failed to load issues",!0)}finally{u(L,!1)}}async function va(s,n){try{await Z.transitionIssue(s,n),I()}catch(c){alert("Failed to transition issue: "+(c instanceof Error?c.message:"Unknown error"))}}function ia(s){u(g,s,!0),I()}var C=Ja(),E=o(t(C),2);V(E,21,()=>q,j,(s,n)=>{var c=Fa();let $;c.__click=()=>ia(a(n));var M=t(c,!0);e(c),m(()=>{$=aa(c,1,"state-tab svelte-1k9wk9x",null,$,{active:a(g)===a(n)}),p(M,a(n))}),l(s,c)}),e(E);var la=o(E,2);{var na=s=>{var n=La();l(s,n)},ca=s=>{var n=X(),c=Y(n);{var $=x=>{var f=Ca(),h=o(t(f),2),P=t(h,!0);e(h);var A=o(h,2);A.__click=I,e(f),m(()=>p(P,a(b))),l(x,f)},M=x=>{var f=X(),h=Y(f);{var P=w=>{var k=Ea(),R=o(t(k),2),v=t(R);e(R),Ia(2),e(k),m(()=>p(v,`No Issues in ${a(g)??""}`)),l(w,k)},A=w=>{var k=Ga();V(k,21,()=>a(F),j,(R,v)=>{var B=Ba(),G=t(B),S=t(G),pa=t(S,!0);e(S);var J=o(S,2),da=t(J,!0);e(J),e(G);var N=o(G,2),_a=t(N,!0);e(N);var Q=o(N,2),z=t(Q);{var ka=r=>{var i=Ma(),_=o(t(i));e(i),m(()=>p(_,` ${a(v).type??""}`)),l(r,i)};y(z,r=>{a(v).type&&r(ka)})}var H=o(z,2);{var ua=r=>{var i=Pa(),_=o(t(i));e(i),m(()=>p(_,` ${a(v).priority??""}`)),l(r,i)};y(H,r=>{a(v).priority&&r(ua)})}var K=o(H,2),ma=o(t(K));e(K),e(Q);var O=o(Q,2),T=t(O);T.__change=r=>va(a(v).id,r.target.value);var U=t(T);U.value=U.__value="";var xa=o(U);V(xa,17,()=>q.filter(r=>r!==a(v).state),j,(r,i)=>{var _=Aa(),fa=t(_,!0);e(_);var W={};m(()=>{p(fa,a(i)),W!==(W=a(i))&&(_.value=(_.__value=a(i))??"")}),l(r,_)}),e(T),e(O),e(B),m((r,i)=>{$a(S,"href",`https://track.cleargrow.io/issue/${a(v).id??""}`),p(pa,a(v).id),aa(J,1,`issue-state state-${r??""}`,"svelte-1k9wk9x"),p(da,a(v).state),p(_a,a(v).summary),p(ma,` ${i??""}`)},[()=>a(v).state.toLowerCase().replace(" ","-"),()=>new Date(a(v).updated).toLocaleDateString()]),l(R,B)}),e(k),l(w,k)};y(h,w=>{a(F).length===0?w(P):w(A,!1)},!0)}l(x,f)};y(c,x=>{a(b)?x($):x(M,!1)},!0)}l(s,n)};y(la,s=>{a(L)?s(na):s(ca,!1)})}e(C),l(ea,C),ba(),oa()}wa(["click","change"]);export{Ha as component};

View File

@@ -1 +1 @@
{"version":"1765463727363"}
{"version":"1765464089844"}

View File

@@ -13,12 +13,12 @@
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="./_app/immutable/entry/start.B4XW_4_n.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CoqDomxY.js">
<link rel="modulepreload" href="./_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="./_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="./_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.DgJvzM75.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="./_app/immutable/chunks/Bm92TOzX.js">
@@ -28,15 +28,15 @@
<div style="display: contents">
<script>
{
__sveltekit_1av60d1 = {
__sveltekit_1jvuf9b = {
base: new URL(".", location).pathname.slice(0, -1)
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.B4XW_4_n.js"),
import("./_app/immutable/entry/app.DgJvzM75.js")
import("./_app/immutable/entry/start.DjFweQ7x.js"),
import("./_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

View File

@@ -13,12 +13,12 @@
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="./_app/immutable/entry/start.B4XW_4_n.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CoqDomxY.js">
<link rel="modulepreload" href="./_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="./_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="./_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.DgJvzM75.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="./_app/immutable/chunks/Bm92TOzX.js">
@@ -28,15 +28,15 @@
<div style="display: contents">
<script>
{
__sveltekit_1av60d1 = {
__sveltekit_1jvuf9b = {
base: new URL(".", location).pathname.slice(0, -1)
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.B4XW_4_n.js"),
import("./_app/immutable/entry/app.DgJvzM75.js")
import("./_app/immutable/entry/start.DjFweQ7x.js"),
import("./_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

View File

@@ -13,12 +13,12 @@
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="./_app/immutable/entry/start.B4XW_4_n.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CoqDomxY.js">
<link rel="modulepreload" href="./_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="./_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="./_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.DgJvzM75.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="./_app/immutable/chunks/Bm92TOzX.js">
@@ -28,15 +28,15 @@
<div style="display: contents">
<script>
{
__sveltekit_1av60d1 = {
__sveltekit_1jvuf9b = {
base: new URL(".", location).pathname.slice(0, -1)
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.B4XW_4_n.js"),
import("./_app/immutable/entry/app.DgJvzM75.js")
import("./_app/immutable/entry/start.DjFweQ7x.js"),
import("./_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

View File

@@ -0,0 +1,47 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Agent Runner Dashboard</title>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="./_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="./_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="./_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="./_app/immutable/chunks/Bm92TOzX.js">
<link rel="modulepreload" href="./_app/immutable/chunks/3ClrRLLp.js">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
__sveltekit_1jvuf9b = {
base: new URL(".", location).pathname.slice(0, -1)
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.DjFweQ7x.js"),
import("./_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});
}
</script>
</div>
</body>
</html>

View File

@@ -13,12 +13,12 @@
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="/_app/immutable/entry/start.B4XW_4_n.js">
<link rel="modulepreload" href="/_app/immutable/chunks/CoqDomxY.js">
<link rel="modulepreload" href="/_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="/_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="/_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="/_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="/_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="/_app/immutable/entry/app.DgJvzM75.js">
<link rel="modulepreload" href="/_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="/_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="/_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="/_app/immutable/chunks/Bm92TOzX.js">
@@ -28,15 +28,15 @@
<div style="display: contents">
<script>
{
__sveltekit_1av60d1 = {
__sveltekit_1jvuf9b = {
base: ""
};
const element = document.currentScript.parentElement;
Promise.all([
import("/_app/immutable/entry/start.B4XW_4_n.js"),
import("/_app/immutable/entry/app.DgJvzM75.js")
import("/_app/immutable/entry/start.DjFweQ7x.js"),
import("/_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

View File

@@ -13,12 +13,12 @@
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<link rel="modulepreload" href="./_app/immutable/entry/start.B4XW_4_n.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CoqDomxY.js">
<link rel="modulepreload" href="./_app/immutable/entry/start.DjFweQ7x.js">
<link rel="modulepreload" href="./_app/immutable/chunks/COMUFPmS.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BkBQXocs.js">
<link rel="modulepreload" href="./_app/immutable/chunks/B6rkT6DW.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CazocS2O.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.DgJvzM75.js">
<link rel="modulepreload" href="./_app/immutable/entry/app.yCpjN6iU.js">
<link rel="modulepreload" href="./_app/immutable/chunks/BceKLUwb.js">
<link rel="modulepreload" href="./_app/immutable/chunks/CwYE-Vvv.js">
<link rel="modulepreload" href="./_app/immutable/chunks/Bm92TOzX.js">
@@ -28,15 +28,15 @@
<div style="display: contents">
<script>
{
__sveltekit_1av60d1 = {
__sveltekit_1jvuf9b = {
base: new URL(".", location).pathname.slice(0, -1)
};
const element = document.currentScript.parentElement;
Promise.all([
import("./_app/immutable/entry/start.B4XW_4_n.js"),
import("./_app/immutable/entry/app.DgJvzM75.js")
import("./_app/immutable/entry/start.DjFweQ7x.js"),
import("./_app/immutable/entry/app.yCpjN6iU.js")
]).then(([kit, app]) => {
kit.start(app, element);
});