feat: add timestamps to process logs and inspector UI

Backend changes:
- Add timestamps to log lines: [2026-01-30T12:32:45.123Z] <line>
- stdout.log and stderr.log get timestamps per line
- combined.log includes [stdout]/[stderr] prefix after timestamp
- Add strip_timestamps query param to GET /process/{id}/logs
- Use time crate with RFC3339 format for timestamps

Frontend changes:
- Add Processes tab to inspector debug panel
- Show list of processes with status badges (running/stopped/killed)
- Click to expand and view logs
- Log viewer options:
  - Select stream: combined, stdout, stderr
  - Toggle strip_timestamps
  - Refresh logs button
- Action buttons: stop (SIGTERM), kill (SIGKILL), delete
- Auto-refresh process list every 5 seconds
This commit is contained in:
Nathan Flurry 2026-01-30 12:43:51 -08:00
parent afb2c74eea
commit db0268b88f
5 changed files with 464 additions and 15 deletions

View file

@ -1,11 +1,12 @@
import { Cloud, PlayCircle, Terminal } from "lucide-react";
import { Cloud, PlayCircle, Terminal, Cpu } from "lucide-react";
import type { AgentInfo, AgentModeInfo, UniversalEvent } from "sandbox-agent";
import AgentsTab from "./AgentsTab";
import EventsTab from "./EventsTab";
import ProcessesTab from "./ProcessesTab";
import RequestLogTab from "./RequestLogTab";
import type { RequestLog } from "../../types/requestLog";
export type DebugTab = "log" | "events" | "agents";
export type DebugTab = "log" | "events" | "agents" | "processes";
const DebugPanel = ({
debugTab,
@ -24,7 +25,9 @@ const DebugPanel = ({
onRefreshAgents,
onInstallAgent,
agentsLoading,
agentsError
agentsError,
baseUrl,
token
}: {
debugTab: DebugTab;
onDebugTabChange: (tab: DebugTab) => void;
@ -43,6 +46,8 @@ const DebugPanel = ({
onInstallAgent: (agentId: string, reinstall: boolean) => void;
agentsLoading: boolean;
agentsError: string | null;
baseUrl: string;
token?: string;
}) => {
return (
<div className="debug-panel">
@ -60,6 +65,10 @@ const DebugPanel = ({
<Cloud className="button-icon" style={{ marginRight: 4, width: 12, height: 12 }} />
Agents
</button>
<button className={`debug-tab ${debugTab === "processes" ? "active" : ""}`} onClick={() => onDebugTabChange("processes")}>
<Cpu className="button-icon" style={{ marginRight: 4, width: 12, height: 12 }} />
Processes
</button>
</div>
<div className="debug-content">
@ -92,6 +101,13 @@ const DebugPanel = ({
error={agentsError}
/>
)}
{debugTab === "processes" && (
<ProcessesTab
baseUrl={baseUrl}
token={token}
/>
)}
</div>
</div>
);