2026-02-19 17:58:53 +00:00
|
|
|
import * as React from "react";
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
import type {
|
|
|
|
|
AgentConfigInfo,
|
|
|
|
|
AgentEvent,
|
|
|
|
|
AgentInfo,
|
|
|
|
|
AgentStatusValue,
|
|
|
|
|
} from "../api/agents";
|
2026-02-19 17:58:53 +00:00
|
|
|
import { agentsApi, subscribeAgentStream } from "../api/agents";
|
2026-02-20 14:42:41 +00:00
|
|
|
import { settingsApi } from "../api/settings";
|
2026-02-19 17:58:53 +00:00
|
|
|
import type { UpcomingStory } from "../api/workflow";
|
|
|
|
|
|
|
|
|
|
const { useCallback, useEffect, useRef, useState } = React;
|
|
|
|
|
|
|
|
|
|
interface AgentPanelProps {
|
|
|
|
|
stories: UpcomingStory[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface AgentState {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
agentName: string;
|
2026-02-19 17:58:53 +00:00
|
|
|
status: AgentStatusValue;
|
|
|
|
|
log: string[];
|
|
|
|
|
sessionId: string | null;
|
|
|
|
|
worktreePath: string | null;
|
2026-02-20 12:48:50 +00:00
|
|
|
baseBranch: string | null;
|
2026-02-19 17:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const STATUS_COLORS: Record<AgentStatusValue, string> = {
|
|
|
|
|
pending: "#e3b341",
|
|
|
|
|
running: "#58a6ff",
|
|
|
|
|
completed: "#7ee787",
|
|
|
|
|
failed: "#ff7b72",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const STATUS_LABELS: Record<AgentStatusValue, string> = {
|
|
|
|
|
pending: "Pending",
|
|
|
|
|
running: "Running",
|
|
|
|
|
completed: "Completed",
|
|
|
|
|
failed: "Failed",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatTimestamp = (value: Date | null): string => {
|
|
|
|
|
if (!value) return "";
|
|
|
|
|
return value.toLocaleTimeString([], {
|
|
|
|
|
hour: "2-digit",
|
|
|
|
|
minute: "2-digit",
|
|
|
|
|
second: "2-digit",
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function StatusBadge({ status }: { status: AgentStatusValue }) {
|
|
|
|
|
return (
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
display: "inline-flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "4px",
|
|
|
|
|
padding: "2px 8px",
|
|
|
|
|
borderRadius: "999px",
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
background: `${STATUS_COLORS[status]}22`,
|
|
|
|
|
color: STATUS_COLORS[status],
|
|
|
|
|
border: `1px solid ${STATUS_COLORS[status]}44`,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{status === "running" && (
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
width: "6px",
|
|
|
|
|
height: "6px",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
background: STATUS_COLORS[status],
|
|
|
|
|
animation: "pulse 1.5s infinite",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{STATUS_LABELS[status]}
|
|
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
function RosterBadge({ agent }: { agent: AgentConfigInfo }) {
|
|
|
|
|
return (
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
display: "inline-flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "4px",
|
|
|
|
|
padding: "2px 8px",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
background: "#ffffff08",
|
|
|
|
|
color: "#888",
|
|
|
|
|
border: "1px solid #333",
|
|
|
|
|
}}
|
|
|
|
|
title={agent.role || agent.name}
|
|
|
|
|
>
|
|
|
|
|
<span style={{ fontWeight: 600, color: "#aaa" }}>{agent.name}</span>
|
|
|
|
|
{agent.model && <span style={{ color: "#666" }}>{agent.model}</span>}
|
|
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Build a composite key for tracking agent state. */
|
|
|
|
|
function agentKey(storyId: string, agentName: string): string {
|
|
|
|
|
return `${storyId}:${agentName}`;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 12:48:50 +00:00
|
|
|
function DiffCommand({
|
|
|
|
|
worktreePath,
|
|
|
|
|
baseBranch,
|
2026-02-20 14:11:53 +00:00
|
|
|
}: {
|
|
|
|
|
worktreePath: string;
|
|
|
|
|
baseBranch: string;
|
|
|
|
|
}) {
|
2026-02-20 12:48:50 +00:00
|
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
|
const command = `cd "${worktreePath}" && git difftool ${baseBranch}...HEAD`;
|
|
|
|
|
|
|
|
|
|
const handleCopy = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await navigator.clipboard.writeText(command);
|
|
|
|
|
setCopied(true);
|
|
|
|
|
setTimeout(() => setCopied(false), 2000);
|
|
|
|
|
} catch {
|
|
|
|
|
// Fallback: select text for manual copy
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "6px",
|
|
|
|
|
marginBottom: "6px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<code
|
|
|
|
|
style={{
|
|
|
|
|
flex: 1,
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
color: "#8b949e",
|
|
|
|
|
background: "#0d1117",
|
|
|
|
|
padding: "4px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #21262d",
|
|
|
|
|
overflow: "hidden",
|
|
|
|
|
textOverflow: "ellipsis",
|
|
|
|
|
whiteSpace: "nowrap",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{command}
|
|
|
|
|
</code>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={handleCopy}
|
|
|
|
|
style={{
|
|
|
|
|
padding: "3px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #30363d",
|
|
|
|
|
background: copied ? "#238636" : "#21262d",
|
|
|
|
|
color: copied ? "#fff" : "#8b949e",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
whiteSpace: "nowrap",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{copied ? "Copied" : "Copy"}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 15:13:30 +00:00
|
|
|
export function EditorCommand({
|
2026-02-20 14:42:41 +00:00
|
|
|
worktreePath,
|
|
|
|
|
editorCommand,
|
|
|
|
|
}: {
|
|
|
|
|
worktreePath: string;
|
|
|
|
|
editorCommand: string;
|
|
|
|
|
}) {
|
|
|
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
|
const command = `${editorCommand} "${worktreePath}"`;
|
|
|
|
|
|
|
|
|
|
const handleCopy = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await navigator.clipboard.writeText(command);
|
|
|
|
|
setCopied(true);
|
|
|
|
|
setTimeout(() => setCopied(false), 2000);
|
|
|
|
|
} catch {
|
|
|
|
|
// Fallback: select text for manual copy
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "6px",
|
|
|
|
|
marginBottom: "6px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<code
|
|
|
|
|
style={{
|
|
|
|
|
flex: 1,
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
color: "#8b949e",
|
|
|
|
|
background: "#0d1117",
|
|
|
|
|
padding: "4px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #21262d",
|
|
|
|
|
overflow: "hidden",
|
|
|
|
|
textOverflow: "ellipsis",
|
|
|
|
|
whiteSpace: "nowrap",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{command}
|
|
|
|
|
</code>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={handleCopy}
|
|
|
|
|
style={{
|
|
|
|
|
padding: "3px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #30363d",
|
|
|
|
|
background: copied ? "#238636" : "#21262d",
|
|
|
|
|
color: copied ? "#fff" : "#8b949e",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
whiteSpace: "nowrap",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{copied ? "Copied" : "Open"}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 17:58:53 +00:00
|
|
|
export function AgentPanel({ stories }: AgentPanelProps) {
|
|
|
|
|
const [agents, setAgents] = useState<Record<string, AgentState>>({});
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const [roster, setRoster] = useState<AgentConfigInfo[]>([]);
|
|
|
|
|
const [expandedKey, setExpandedKey] = useState<string | null>(null);
|
2026-02-19 17:58:53 +00:00
|
|
|
const [actionError, setActionError] = useState<string | null>(null);
|
|
|
|
|
const [lastRefresh, setLastRefresh] = useState<Date | null>(null);
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const [selectorStory, setSelectorStory] = useState<string | null>(null);
|
2026-02-20 14:42:41 +00:00
|
|
|
const [editorCommand, setEditorCommand] = useState<string | null>(null);
|
|
|
|
|
const [editorInput, setEditorInput] = useState<string>("");
|
|
|
|
|
const [editingEditor, setEditingEditor] = useState(false);
|
2026-02-19 17:58:53 +00:00
|
|
|
const cleanupRefs = useRef<Record<string, () => void>>({});
|
|
|
|
|
const logEndRefs = useRef<Record<string, HTMLDivElement | null>>({});
|
|
|
|
|
|
2026-02-20 14:42:41 +00:00
|
|
|
// Load roster, existing agents, and editor preference on mount
|
2026-02-19 17:58:53 +00:00
|
|
|
useEffect(() => {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
agentsApi
|
|
|
|
|
.getAgentConfig()
|
|
|
|
|
.then(setRoster)
|
|
|
|
|
.catch((err) => console.error("Failed to load agent config:", err));
|
|
|
|
|
|
2026-02-19 17:58:53 +00:00
|
|
|
agentsApi
|
|
|
|
|
.listAgents()
|
|
|
|
|
.then((agentList) => {
|
|
|
|
|
const agentMap: Record<string, AgentState> = {};
|
|
|
|
|
for (const a of agentList) {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const key = agentKey(a.story_id, a.agent_name);
|
|
|
|
|
agentMap[key] = {
|
|
|
|
|
agentName: a.agent_name,
|
2026-02-19 17:58:53 +00:00
|
|
|
status: a.status,
|
|
|
|
|
log: [],
|
|
|
|
|
sessionId: a.session_id,
|
|
|
|
|
worktreePath: a.worktree_path,
|
2026-02-20 12:48:50 +00:00
|
|
|
baseBranch: a.base_branch,
|
2026-02-19 17:58:53 +00:00
|
|
|
};
|
|
|
|
|
if (a.status === "running" || a.status === "pending") {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
subscribeToAgent(a.story_id, a.agent_name);
|
2026-02-19 17:58:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setAgents(agentMap);
|
|
|
|
|
setLastRefresh(new Date());
|
|
|
|
|
})
|
|
|
|
|
.catch((err) => console.error("Failed to load agents:", err));
|
|
|
|
|
|
2026-02-20 14:42:41 +00:00
|
|
|
settingsApi
|
|
|
|
|
.getEditorCommand()
|
|
|
|
|
.then((s) => {
|
|
|
|
|
setEditorCommand(s.editor_command);
|
|
|
|
|
setEditorInput(s.editor_command ?? "");
|
|
|
|
|
})
|
|
|
|
|
.catch((err) => console.error("Failed to load editor command:", err));
|
|
|
|
|
|
2026-02-19 17:58:53 +00:00
|
|
|
return () => {
|
|
|
|
|
for (const cleanup of Object.values(cleanupRefs.current)) {
|
|
|
|
|
cleanup();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, []);
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const subscribeToAgent = useCallback((storyId: string, agentName: string) => {
|
|
|
|
|
const key = agentKey(storyId, agentName);
|
|
|
|
|
cleanupRefs.current[key]?.();
|
2026-02-19 17:58:53 +00:00
|
|
|
|
|
|
|
|
const cleanup = subscribeAgentStream(
|
|
|
|
|
storyId,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
agentName,
|
2026-02-19 17:58:53 +00:00
|
|
|
(event: AgentEvent) => {
|
|
|
|
|
setAgents((prev) => {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const current = prev[key] ?? {
|
|
|
|
|
agentName,
|
2026-02-19 17:58:53 +00:00
|
|
|
status: "pending" as AgentStatusValue,
|
|
|
|
|
log: [],
|
|
|
|
|
sessionId: null,
|
|
|
|
|
worktreePath: null,
|
2026-02-20 12:48:50 +00:00
|
|
|
baseBranch: null,
|
2026-02-19 17:58:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (event.type) {
|
|
|
|
|
case "status":
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
[key]: {
|
2026-02-19 17:58:53 +00:00
|
|
|
...current,
|
|
|
|
|
status: (event.status as AgentStatusValue) ?? current.status,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
case "output":
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
[key]: {
|
2026-02-19 17:58:53 +00:00
|
|
|
...current,
|
|
|
|
|
log: [...current.log, event.text ?? ""],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
case "done":
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
[key]: {
|
2026-02-19 17:58:53 +00:00
|
|
|
...current,
|
|
|
|
|
status: "completed",
|
|
|
|
|
sessionId: event.session_id ?? current.sessionId,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
case "error":
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
[key]: {
|
2026-02-19 17:58:53 +00:00
|
|
|
...current,
|
|
|
|
|
status: "failed",
|
|
|
|
|
log: [
|
|
|
|
|
...current.log,
|
|
|
|
|
`[ERROR] ${event.message ?? "Unknown error"}`,
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
default:
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
// SSE error — agent may not be streaming yet
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
cleanupRefs.current[key] = cleanup;
|
2026-02-19 17:58:53 +00:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Auto-scroll log when expanded
|
|
|
|
|
useEffect(() => {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
if (expandedKey) {
|
|
|
|
|
const el = logEndRefs.current[expandedKey];
|
2026-02-19 17:58:53 +00:00
|
|
|
el?.scrollIntoView({ behavior: "smooth" });
|
|
|
|
|
}
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
}, [expandedKey, agents]);
|
2026-02-19 17:58:53 +00:00
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const handleStart = async (storyId: string, agentName?: string) => {
|
2026-02-19 17:58:53 +00:00
|
|
|
setActionError(null);
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
setSelectorStory(null);
|
2026-02-19 17:58:53 +00:00
|
|
|
try {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const info: AgentInfo = await agentsApi.startAgent(storyId, agentName);
|
|
|
|
|
const key = agentKey(info.story_id, info.agent_name);
|
2026-02-19 17:58:53 +00:00
|
|
|
setAgents((prev) => ({
|
|
|
|
|
...prev,
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
[key]: {
|
|
|
|
|
agentName: info.agent_name,
|
2026-02-19 17:58:53 +00:00
|
|
|
status: info.status,
|
|
|
|
|
log: [],
|
|
|
|
|
sessionId: info.session_id,
|
|
|
|
|
worktreePath: info.worktree_path,
|
2026-02-20 12:48:50 +00:00
|
|
|
baseBranch: info.base_branch,
|
2026-02-19 17:58:53 +00:00
|
|
|
},
|
|
|
|
|
}));
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
setExpandedKey(key);
|
|
|
|
|
subscribeToAgent(info.story_id, info.agent_name);
|
2026-02-19 17:58:53 +00:00
|
|
|
} catch (err) {
|
|
|
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
|
|
|
setActionError(`Failed to start agent for ${storyId}: ${message}`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const handleStop = async (storyId: string, agentName: string) => {
|
2026-02-19 17:58:53 +00:00
|
|
|
setActionError(null);
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const key = agentKey(storyId, agentName);
|
2026-02-19 17:58:53 +00:00
|
|
|
try {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
await agentsApi.stopAgent(storyId, agentName);
|
|
|
|
|
cleanupRefs.current[key]?.();
|
|
|
|
|
delete cleanupRefs.current[key];
|
2026-02-19 17:58:53 +00:00
|
|
|
setAgents((prev) => {
|
|
|
|
|
const next = { ...prev };
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
delete next[key];
|
2026-02-19 17:58:53 +00:00
|
|
|
return next;
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
|
|
|
setActionError(`Failed to stop agent for ${storyId}: ${message}`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const handleRunClick = (storyId: string) => {
|
|
|
|
|
if (roster.length <= 1) {
|
|
|
|
|
handleStart(storyId);
|
|
|
|
|
} else {
|
|
|
|
|
setSelectorStory(selectorStory === storyId ? null : storyId);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-20 14:42:41 +00:00
|
|
|
const handleSaveEditor = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const trimmed = editorInput.trim() || null;
|
|
|
|
|
const result = await settingsApi.setEditorCommand(trimmed);
|
|
|
|
|
setEditorCommand(result.editor_command);
|
|
|
|
|
setEditorInput(result.editor_command ?? "");
|
|
|
|
|
setEditingEditor(false);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
|
|
|
setActionError(`Failed to save editor: ${message}`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
/** Get all active agent keys for a story. */
|
|
|
|
|
const getActiveKeysForStory = (storyId: string): string[] => {
|
|
|
|
|
return Object.keys(agents).filter((key) => {
|
|
|
|
|
const a = agents[key];
|
|
|
|
|
return (
|
|
|
|
|
key.startsWith(`${storyId}:`) &&
|
|
|
|
|
(a.status === "running" || a.status === "pending")
|
|
|
|
|
);
|
|
|
|
|
});
|
2026-02-19 17:58:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
border: "1px solid #333",
|
|
|
|
|
borderRadius: "10px",
|
|
|
|
|
padding: "12px 16px",
|
|
|
|
|
background: "#1f1f1f",
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
gap: "8px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "space-between",
|
|
|
|
|
gap: "12px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "8px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div style={{ fontWeight: 600 }}>Agents</div>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
color: "#777",
|
|
|
|
|
fontFamily: "monospace",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{Object.values(agents).filter((a) => a.status === "running").length}{" "}
|
|
|
|
|
running
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{lastRefresh && (
|
|
|
|
|
<div style={{ fontSize: "0.7em", color: "#555" }}>
|
|
|
|
|
Loaded {formatTimestamp(lastRefresh)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-20 14:42:41 +00:00
|
|
|
{/* Editor preference */}
|
|
|
|
|
<div style={{ display: "flex", alignItems: "center", gap: "6px" }}>
|
|
|
|
|
<span style={{ fontSize: "0.75em", color: "#666" }}>Editor:</span>
|
|
|
|
|
{editingEditor ? (
|
|
|
|
|
<>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={editorInput}
|
|
|
|
|
onChange={(e) => setEditorInput(e.target.value)}
|
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
|
if (e.key === "Enter") handleSaveEditor();
|
|
|
|
|
if (e.key === "Escape") setEditingEditor(false);
|
|
|
|
|
}}
|
|
|
|
|
placeholder="zed, code, cursor..."
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
background: "#111",
|
|
|
|
|
border: "1px solid #444",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
color: "#ccc",
|
|
|
|
|
padding: "2px 6px",
|
|
|
|
|
width: "120px",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={handleSaveEditor}
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
padding: "2px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #238636",
|
|
|
|
|
background: "#238636",
|
|
|
|
|
color: "#fff",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setEditingEditor(false)}
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
padding: "2px 8px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
border: "1px solid #444",
|
|
|
|
|
background: "none",
|
|
|
|
|
color: "#888",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setEditingEditor(true)}
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
background: "none",
|
|
|
|
|
border: "1px solid #333",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
color: editorCommand ? "#aaa" : "#555",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
padding: "2px 8px",
|
|
|
|
|
fontFamily: editorCommand ? "monospace" : "inherit",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{editorCommand ?? "Set editor..."}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
{/* Roster badges */}
|
|
|
|
|
{roster.length > 0 && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
gap: "4px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{roster.map((a) => (
|
|
|
|
|
<RosterBadge key={`roster-${a.name}`} agent={a} />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-02-19 17:58:53 +00:00
|
|
|
{actionError && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.85em",
|
|
|
|
|
color: "#ff7b72",
|
|
|
|
|
padding: "4px 8px",
|
|
|
|
|
background: "#ff7b7211",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{actionError}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{stories.length === 0 ? (
|
|
|
|
|
<div style={{ fontSize: "0.85em", color: "#aaa" }}>
|
|
|
|
|
No stories available. Add stories to .story_kit/stories/upcoming/.
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
gap: "6px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{stories.map((story) => {
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
const activeKeys = getActiveKeysForStory(story.story_id);
|
|
|
|
|
const hasActive = activeKeys.length > 0;
|
|
|
|
|
|
|
|
|
|
// Gather all agent states for this story
|
|
|
|
|
const storyAgentEntries = Object.entries(agents).filter(([key]) =>
|
|
|
|
|
key.startsWith(`${story.story_id}:`),
|
|
|
|
|
);
|
2026-02-19 17:58:53 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={`agent-${story.story_id}`}
|
|
|
|
|
style={{
|
|
|
|
|
border: "1px solid #2a2a2a",
|
|
|
|
|
borderRadius: "8px",
|
|
|
|
|
background: "#191919",
|
|
|
|
|
overflow: "hidden",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
padding: "8px 12px",
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "8px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
2026-02-20 13:17:20 +00:00
|
|
|
onClick={() => {
|
|
|
|
|
const isExpanded =
|
|
|
|
|
expandedKey?.startsWith(`${story.story_id}:`) ||
|
|
|
|
|
expandedKey === story.story_id;
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
setExpandedKey(
|
2026-02-20 13:17:20 +00:00
|
|
|
isExpanded
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
? null
|
|
|
|
|
: (storyAgentEntries[0]?.[0] ?? story.story_id),
|
2026-02-20 13:17:20 +00:00
|
|
|
);
|
|
|
|
|
}}
|
2026-02-19 17:58:53 +00:00
|
|
|
onKeyDown={(e) => {
|
|
|
|
|
if (e.key === "Enter" || e.key === " ") {
|
2026-02-20 13:17:20 +00:00
|
|
|
const isExpanded =
|
|
|
|
|
expandedKey?.startsWith(`${story.story_id}:`) ||
|
|
|
|
|
expandedKey === story.story_id;
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
setExpandedKey(
|
2026-02-20 13:17:20 +00:00
|
|
|
isExpanded
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
? null
|
|
|
|
|
: (storyAgentEntries[0]?.[0] ?? story.story_id),
|
|
|
|
|
);
|
2026-02-19 17:58:53 +00:00
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
style={{
|
|
|
|
|
background: "none",
|
|
|
|
|
border: "none",
|
|
|
|
|
color: "#aaa",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
fontSize: "0.8em",
|
|
|
|
|
padding: "0 4px",
|
2026-02-20 13:17:20 +00:00
|
|
|
transform:
|
|
|
|
|
expandedKey?.startsWith(`${story.story_id}:`) ||
|
|
|
|
|
expandedKey === story.story_id
|
|
|
|
|
? "rotate(90deg)"
|
|
|
|
|
: "rotate(0deg)",
|
2026-02-19 17:58:53 +00:00
|
|
|
transition: "transform 0.15s",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
▶
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
flex: 1,
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
fontSize: "0.9em",
|
|
|
|
|
overflow: "hidden",
|
|
|
|
|
textOverflow: "ellipsis",
|
|
|
|
|
whiteSpace: "nowrap",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{story.name ?? story.story_id}
|
|
|
|
|
</div>
|
|
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
{storyAgentEntries.map(([key, a]) => (
|
|
|
|
|
<span
|
|
|
|
|
key={`badge-${key}`}
|
|
|
|
|
style={{
|
|
|
|
|
display: "inline-flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: "4px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.7em",
|
|
|
|
|
color: "#666",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{a.agentName}
|
|
|
|
|
</span>
|
|
|
|
|
<StatusBadge status={a.status} />
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
2026-02-19 17:58:53 +00:00
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
{hasActive ? (
|
2026-02-19 17:58:53 +00:00
|
|
|
<button
|
|
|
|
|
type="button"
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
onClick={() => {
|
|
|
|
|
for (const key of activeKeys) {
|
|
|
|
|
const a = agents[key];
|
|
|
|
|
if (a) {
|
|
|
|
|
handleStop(story.story_id, a.agentName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
2026-02-19 17:58:53 +00:00
|
|
|
style={{
|
|
|
|
|
padding: "4px 10px",
|
|
|
|
|
borderRadius: "999px",
|
|
|
|
|
border: "1px solid #ff7b7244",
|
|
|
|
|
background: "#ff7b7211",
|
|
|
|
|
color: "#ff7b72",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Stop
|
|
|
|
|
</button>
|
|
|
|
|
) : (
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
<div style={{ position: "relative" }}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => handleRunClick(story.story_id)}
|
2026-02-19 17:58:53 +00:00
|
|
|
style={{
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
padding: "4px 10px",
|
|
|
|
|
borderRadius: "999px",
|
|
|
|
|
border: "1px solid #7ee78744",
|
|
|
|
|
background: "#7ee78711",
|
|
|
|
|
color: "#7ee787",
|
|
|
|
|
cursor: "pointer",
|
2026-02-19 17:58:53 +00:00
|
|
|
fontSize: "0.75em",
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
fontWeight: 600,
|
2026-02-19 17:58:53 +00:00
|
|
|
}}
|
|
|
|
|
>
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
Run
|
|
|
|
|
</button>
|
|
|
|
|
{selectorStory === story.story_id &&
|
|
|
|
|
roster.length > 1 && (
|
2026-02-19 17:58:53 +00:00
|
|
|
<div
|
|
|
|
|
style={{
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
position: "absolute",
|
|
|
|
|
top: "100%",
|
|
|
|
|
right: 0,
|
|
|
|
|
marginTop: "4px",
|
|
|
|
|
background: "#222",
|
|
|
|
|
border: "1px solid #444",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
padding: "4px 0",
|
|
|
|
|
zIndex: 10,
|
|
|
|
|
minWidth: "160px",
|
2026-02-19 17:58:53 +00:00
|
|
|
}}
|
|
|
|
|
>
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
{roster.map((r) => (
|
|
|
|
|
<button
|
|
|
|
|
key={`sel-${r.name}`}
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() =>
|
|
|
|
|
handleStart(story.story_id, r.name)
|
|
|
|
|
}
|
|
|
|
|
style={{
|
|
|
|
|
display: "block",
|
|
|
|
|
width: "100%",
|
|
|
|
|
padding: "6px 12px",
|
|
|
|
|
background: "none",
|
|
|
|
|
border: "none",
|
|
|
|
|
color: "#ccc",
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
textAlign: "left",
|
|
|
|
|
fontSize: "0.8em",
|
|
|
|
|
}}
|
|
|
|
|
onMouseEnter={(e) => {
|
|
|
|
|
(
|
|
|
|
|
e.target as HTMLButtonElement
|
|
|
|
|
).style.background = "#333";
|
|
|
|
|
}}
|
|
|
|
|
onMouseLeave={(e) => {
|
|
|
|
|
(
|
|
|
|
|
e.target as HTMLButtonElement
|
|
|
|
|
).style.background = "none";
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div style={{ fontWeight: 600 }}>{r.name}</div>
|
|
|
|
|
{r.role && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.85em",
|
|
|
|
|
color: "#888",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{r.role}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
2026-02-19 17:58:53 +00:00
|
|
|
</div>
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-20 13:17:20 +00:00
|
|
|
{/* Empty state when expanded with no agents */}
|
2026-02-20 14:11:53 +00:00
|
|
|
{expandedKey === story.story_id &&
|
|
|
|
|
storyAgentEntries.length === 0 && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
borderTop: "1px solid #2a2a2a",
|
|
|
|
|
padding: "12px",
|
|
|
|
|
fontSize: "0.8em",
|
|
|
|
|
color: "#555",
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
No agents started. Use the Run button to start an agent.
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-02-20 13:17:20 +00:00
|
|
|
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
{/* Expanded detail per agent */}
|
|
|
|
|
{storyAgentEntries.map(([key, a]) => {
|
|
|
|
|
if (expandedKey !== key) return null;
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={`detail-${key}`}
|
|
|
|
|
style={{
|
|
|
|
|
borderTop: "1px solid #2a2a2a",
|
|
|
|
|
padding: "8px 12px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
color: "#888",
|
|
|
|
|
marginBottom: "4px",
|
|
|
|
|
fontWeight: 600,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{a.agentName}
|
|
|
|
|
</div>
|
|
|
|
|
{a.worktreePath && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: "0.75em",
|
|
|
|
|
color: "#666",
|
|
|
|
|
fontFamily: "monospace",
|
|
|
|
|
marginBottom: "6px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Worktree: {a.worktreePath}
|
|
|
|
|
</div>
|
2026-02-19 17:58:53 +00:00
|
|
|
)}
|
2026-02-20 12:48:50 +00:00
|
|
|
{a.worktreePath && (
|
|
|
|
|
<DiffCommand
|
|
|
|
|
worktreePath={a.worktreePath}
|
|
|
|
|
baseBranch={a.baseBranch ?? "master"}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2026-02-19 17:58:53 +00:00
|
|
|
<div
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
style={{
|
|
|
|
|
maxHeight: "300px",
|
|
|
|
|
overflowY: "auto",
|
|
|
|
|
background: "#111",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
padding: "8px",
|
|
|
|
|
fontFamily: "monospace",
|
|
|
|
|
fontSize: "0.8em",
|
|
|
|
|
lineHeight: "1.5",
|
|
|
|
|
color: "#ccc",
|
|
|
|
|
whiteSpace: "pre-wrap",
|
|
|
|
|
wordBreak: "break-word",
|
2026-02-19 17:58:53 +00:00
|
|
|
}}
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
>
|
|
|
|
|
{a.log.length === 0 ? (
|
|
|
|
|
<span style={{ color: "#555" }}>
|
|
|
|
|
{a.status === "pending" || a.status === "running"
|
|
|
|
|
? "Waiting for output..."
|
|
|
|
|
: "No output captured."}
|
|
|
|
|
</span>
|
|
|
|
|
) : (
|
|
|
|
|
a.log.map((line, i) => (
|
|
|
|
|
<div
|
|
|
|
|
key={`log-${key}-${i.toString()}`}
|
|
|
|
|
style={{
|
|
|
|
|
color: line.startsWith("[ERROR]")
|
|
|
|
|
? "#ff7b72"
|
|
|
|
|
: "#ccc",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{line}
|
|
|
|
|
</div>
|
|
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
<div
|
|
|
|
|
ref={(el) => {
|
|
|
|
|
logEndRefs.current[key] = el;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-02-19 17:58:53 +00:00
|
|
|
</div>
|
Accept story 34: Per-Project Agent Configuration and Role Definitions
Replace single [agent] config with multi-agent [[agent]] roster system.
Each agent has name, role, model, allowed_tools, max_turns, max_budget_usd,
and system_prompt fields that map to Claude CLI flags at spawn time.
- AgentConfig expanded with structured fields, validated at startup (panics
on duplicate names, empty names, non-positive budgets/turns)
- Backwards-compatible: legacy [agent] format auto-wraps with deprecation warning
- AgentPool uses composite "story_id:agent_name" keys for concurrent agents
- agent_name added to AgentEvent variants, AgentInfo, start/stop/subscribe APIs
- GET /agents/config returns roster, POST /agents/config/reload hot-reloads
- POST /agents/start accepts optional agent_name, /agents/stop requires it
- SSE route updated to /agents/:story_id/:agent_name/stream
- Frontend: roster badges, agent selector dropdown, composite-key state
- Project root initialized to cwd at startup so config endpoints work immediately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:46:14 +00:00
|
|
|
);
|
|
|
|
|
})}
|
2026-02-19 17:58:53 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|