refactor(app): unified panel state machine for mobile sidebars
Replace separate sidebar stores with a unified panel store that uses a discriminated union state machine on mobile. This makes it impossible for both the agent list and file explorer sidebars to be open at the same time on mobile. Mobile state machine (mobileView): - 'agent': Main agent view (no overlay panel) - 'agent-list': Agent list sidebar (left overlay) - 'file-explorer': File explorer sidebar (right overlay) Desktop retains independent boolean toggles since sidebars sit alongside content rather than overlaying it. Key changes: - Created stores/panel-store.ts with unified state - Deleted stores/sidebar-store.ts and explorer-sidebar-store.ts - Updated all components to use new panel store - Animation contexts derive isOpen from unified state
This commit is contained in:
@@ -4,9 +4,7 @@ import {
|
||||
AGENT_LIFECYCLE_STATUSES,
|
||||
type AgentLifecycleStatus,
|
||||
} from "../../shared/agent-lifecycle.js";
|
||||
import { getRootLogger } from "../logger.js";
|
||||
|
||||
const logger = getRootLogger().child({ module: "agent", component: "agent-manager" });
|
||||
import type { Logger } from "pino";
|
||||
|
||||
import type {
|
||||
AgentCapabilityFlags,
|
||||
@@ -61,6 +59,7 @@ export type AgentManagerOptions = {
|
||||
registry?: AgentRegistry;
|
||||
agentControlMcp?: AgentControlMcpConfig;
|
||||
onAgentAttention?: AgentAttentionCallback;
|
||||
logger: Logger;
|
||||
};
|
||||
|
||||
export type WaitForAgentOptions = {
|
||||
@@ -187,14 +186,16 @@ export class AgentManager {
|
||||
private readonly previousStatuses = new Map<string, AgentLifecycleStatus>();
|
||||
private readonly agentControlMcp?: AgentControlMcpConfig;
|
||||
private onAgentAttention?: AgentAttentionCallback;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(options?: AgentManagerOptions) {
|
||||
constructor(options: AgentManagerOptions) {
|
||||
this.maxTimelineItems =
|
||||
options?.maxTimelineItems ?? DEFAULT_MAX_TIMELINE_ITEMS;
|
||||
this.idFactory = options?.idFactory ?? (() => randomUUID());
|
||||
this.registry = options?.registry;
|
||||
this.agentControlMcp = options?.agentControlMcp;
|
||||
this.onAgentAttention = options?.onAgentAttention;
|
||||
this.logger = options.logger.child({ module: "agent", component: "agent-manager" });
|
||||
if (options?.clients) {
|
||||
for (const [provider, client] of Object.entries(options.clients)) {
|
||||
if (client) {
|
||||
@@ -271,7 +272,7 @@ export class AgentManager {
|
||||
});
|
||||
descriptors.push(...entries);
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
{ err: error, provider },
|
||||
"Failed to list persisted agents for provider"
|
||||
);
|
||||
@@ -358,7 +359,7 @@ export class AgentManager {
|
||||
try {
|
||||
await existing.session.close();
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
{ err: error, agentId },
|
||||
"Failed to close previous session during refresh"
|
||||
);
|
||||
@@ -549,7 +550,7 @@ export class AgentManager {
|
||||
try {
|
||||
await agent.session.interrupt();
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
this.logger.error(
|
||||
{ err: error, agentId },
|
||||
"Failed to interrupt session"
|
||||
);
|
||||
@@ -561,7 +562,7 @@ export class AgentManager {
|
||||
await pendingRun.return(undefined as unknown as AgentStreamEvent);
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
this.logger.error(
|
||||
{ err: error, agentId },
|
||||
"Failed to cancel run"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user