@finityno/claude-code-acp 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,193 @@
1
+ import { AgentSideConnection } from "@agentclientprotocol/sdk";
2
+ import { Logger } from "./acp-agent.js";
3
+ /**
4
+ * Subagent status lifecycle
5
+ */
6
+ export type SubagentStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
7
+ /**
8
+ * Subagent type from Claude Code Task tool
9
+ */
10
+ export type SubagentType = "Bash" | "general-purpose" | "statusline-setup" | "Explore" | "Plan" | "claude-code-guide" | string;
11
+ /**
12
+ * Tracked subagent information
13
+ */
14
+ export interface TrackedSubagent {
15
+ /** Unique ID for this subagent (same as tool_use_id) */
16
+ id: string;
17
+ /** Parent session ID where this subagent was spawned */
18
+ parentSessionId: string;
19
+ /** Parent tool use ID if this is a nested subagent */
20
+ parentToolUseId?: string;
21
+ /** Type of subagent */
22
+ subagentType: SubagentType;
23
+ /** Short description of what the subagent is doing */
24
+ description: string;
25
+ /** Full prompt given to the subagent */
26
+ prompt: string;
27
+ /** Model used for this subagent (if specified) */
28
+ model?: "sonnet" | "opus" | "haiku";
29
+ /** Current status */
30
+ status: SubagentStatus;
31
+ /** Timestamp when subagent was created */
32
+ createdAt: number;
33
+ /** Timestamp when subagent started running */
34
+ startedAt?: number;
35
+ /** Timestamp when subagent completed */
36
+ completedAt?: number;
37
+ /** Result from the subagent (if completed) */
38
+ result?: unknown;
39
+ /** Error message (if failed) */
40
+ error?: string;
41
+ /** Whether this subagent is running in background */
42
+ runInBackground: boolean;
43
+ /** Maximum turns allowed */
44
+ maxTurns?: number;
45
+ /** Agent ID returned by Claude Code (for resume capability) */
46
+ agentId?: string;
47
+ }
48
+ /**
49
+ * Subagent event types for notifications
50
+ */
51
+ export type SubagentEventType = "subagent_started" | "subagent_progress" | "subagent_completed" | "subagent_failed" | "subagent_cancelled";
52
+ /**
53
+ * Metadata for subagent-related notifications
54
+ */
55
+ export interface SubagentUpdateMeta {
56
+ claudeCode?: {
57
+ subagent: {
58
+ id: string;
59
+ eventType: SubagentEventType;
60
+ subagentType: SubagentType;
61
+ description: string;
62
+ status: SubagentStatus;
63
+ parentSessionId: string;
64
+ parentToolUseId?: string;
65
+ model?: string;
66
+ runInBackground: boolean;
67
+ agentId?: string;
68
+ /** Duration in milliseconds (for completed/failed events) */
69
+ durationMs?: number;
70
+ };
71
+ };
72
+ }
73
+ /**
74
+ * Input structure for the Task tool
75
+ */
76
+ export interface TaskToolInput {
77
+ description: string;
78
+ prompt: string;
79
+ subagent_type: SubagentType;
80
+ model?: "sonnet" | "opus" | "haiku";
81
+ max_turns?: number;
82
+ run_in_background?: boolean;
83
+ resume?: string;
84
+ }
85
+ export type SubagentEventListener = (subagent: TrackedSubagent, data?: unknown) => void | Promise<void>;
86
+ export interface SubagentStats {
87
+ total: number;
88
+ pending: number;
89
+ running: number;
90
+ completed: number;
91
+ failed: number;
92
+ cancelled: number;
93
+ byType: Record<string, number>;
94
+ averageDurationMs?: number;
95
+ }
96
+ /**
97
+ * SubagentTracker manages the lifecycle of all subagents spawned via the Task tool
98
+ */
99
+ export declare class SubagentTracker {
100
+ /** Map of subagent ID to tracked subagent data */
101
+ private subagents;
102
+ /** Map of session ID to subagent IDs in that session */
103
+ private sessionSubagents;
104
+ /** Event listeners for subagent lifecycle events */
105
+ private listeners;
106
+ private client;
107
+ private logger;
108
+ constructor(client?: AgentSideConnection | null, logger?: Logger);
109
+ /**
110
+ * Track a new subagent when Task tool is called
111
+ */
112
+ trackSubagent(toolUseId: string, sessionId: string, input: TaskToolInput, parentToolUseId?: string): TrackedSubagent;
113
+ /**
114
+ * Mark a subagent as started/running
115
+ */
116
+ startSubagent(toolUseId: string): Promise<void>;
117
+ /**
118
+ * Mark a subagent as completed successfully
119
+ */
120
+ completeSubagent(toolUseId: string, result?: unknown, agentId?: string): Promise<void>;
121
+ /**
122
+ * Mark a subagent as failed
123
+ */
124
+ failSubagent(toolUseId: string, error: string): Promise<void>;
125
+ /**
126
+ * Mark a subagent as cancelled
127
+ */
128
+ cancelSubagent(toolUseId: string): Promise<void>;
129
+ /**
130
+ * Send progress update for a running subagent
131
+ */
132
+ updateProgress(toolUseId: string, progressData?: unknown): Promise<void>;
133
+ /**
134
+ * Get a tracked subagent by ID
135
+ */
136
+ getSubagent(toolUseId: string): TrackedSubagent | undefined;
137
+ /**
138
+ * Get all subagents for a session
139
+ */
140
+ getSessionSubagents(sessionId: string): TrackedSubagent[];
141
+ /**
142
+ * Get all currently running subagents
143
+ */
144
+ getRunningSubagents(): TrackedSubagent[];
145
+ /**
146
+ * Get all subagents (for debugging/monitoring)
147
+ */
148
+ getAllSubagents(): TrackedSubagent[];
149
+ /**
150
+ * Check if a tool use ID is a Task tool (subagent)
151
+ */
152
+ isSubagent(toolUseId: string): boolean;
153
+ /**
154
+ * Add event listener for subagent lifecycle events
155
+ */
156
+ addEventListener(event: SubagentEventType, listener: SubagentEventListener): void;
157
+ /**
158
+ * Remove event listener
159
+ */
160
+ removeEventListener(event: SubagentEventType, listener: SubagentEventListener): void;
161
+ /**
162
+ * Clean up completed subagents older than given age (in ms)
163
+ */
164
+ cleanup(maxAgeMs?: number): number;
165
+ /**
166
+ * Get statistics about subagents
167
+ */
168
+ getStats(): SubagentStats;
169
+ /**
170
+ * Clear all tracked subagents (useful for testing)
171
+ */
172
+ clear(): void;
173
+ private emitEvent;
174
+ private sendSubagentNotification;
175
+ private getDuration;
176
+ private countByType;
177
+ private calculateAverageDuration;
178
+ }
179
+ /**
180
+ * Utility to check if a tool input is for the Task tool
181
+ */
182
+ export declare function isTaskToolInput(input: unknown): input is TaskToolInput;
183
+ /**
184
+ * Extract subagent metadata from Task tool input
185
+ */
186
+ export declare function extractSubagentMeta(input: TaskToolInput): {
187
+ description: string;
188
+ subagentType: string;
189
+ model?: string;
190
+ runInBackground: boolean;
191
+ maxTurns?: number;
192
+ };
193
+ //# sourceMappingURL=subagent-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-tracker.d.ts","sourceRoot":"","sources":["../src/subagent-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * SubagentTracker manages the lifecycle of all subagents spawned via the Task tool
3
+ */
4
+ export class SubagentTracker {
5
+ constructor(client = null, logger = console) {
6
+ /** Map of subagent ID to tracked subagent data */
7
+ this.subagents = new Map();
8
+ /** Map of session ID to subagent IDs in that session */
9
+ this.sessionSubagents = new Map();
10
+ /** Event listeners for subagent lifecycle events */
11
+ this.listeners = new Map();
12
+ this.client = client;
13
+ this.logger = logger;
14
+ }
15
+ /**
16
+ * Track a new subagent when Task tool is called
17
+ */
18
+ trackSubagent(toolUseId, sessionId, input, parentToolUseId) {
19
+ const subagent = {
20
+ id: toolUseId,
21
+ parentSessionId: sessionId,
22
+ parentToolUseId,
23
+ subagentType: input.subagent_type,
24
+ description: input.description,
25
+ prompt: input.prompt,
26
+ model: input.model,
27
+ status: "pending",
28
+ createdAt: Date.now(),
29
+ runInBackground: input.run_in_background ?? false,
30
+ maxTurns: input.max_turns,
31
+ };
32
+ this.subagents.set(toolUseId, subagent);
33
+ // Track by session
34
+ if (!this.sessionSubagents.has(sessionId)) {
35
+ this.sessionSubagents.set(sessionId, new Set());
36
+ }
37
+ this.sessionSubagents.get(sessionId).add(toolUseId);
38
+ this.logger.log(`[SubagentTracker] Tracked new subagent: ${toolUseId} (${input.subagent_type}: ${input.description})`);
39
+ return subagent;
40
+ }
41
+ /**
42
+ * Mark a subagent as started/running
43
+ */
44
+ async startSubagent(toolUseId) {
45
+ const subagent = this.subagents.get(toolUseId);
46
+ if (!subagent) {
47
+ this.logger.error(`[SubagentTracker] Cannot start unknown subagent: ${toolUseId}`);
48
+ return;
49
+ }
50
+ subagent.status = "running";
51
+ subagent.startedAt = Date.now();
52
+ await this.emitEvent("subagent_started", subagent);
53
+ await this.sendSubagentNotification(subagent, "subagent_started");
54
+ }
55
+ /**
56
+ * Mark a subagent as completed successfully
57
+ */
58
+ async completeSubagent(toolUseId, result, agentId) {
59
+ const subagent = this.subagents.get(toolUseId);
60
+ if (!subagent) {
61
+ this.logger.error(`[SubagentTracker] Cannot complete unknown subagent: ${toolUseId}`);
62
+ return;
63
+ }
64
+ subagent.status = "completed";
65
+ subagent.completedAt = Date.now();
66
+ subagent.result = result;
67
+ if (agentId) {
68
+ subagent.agentId = agentId;
69
+ }
70
+ await this.emitEvent("subagent_completed", subagent);
71
+ await this.sendSubagentNotification(subagent, "subagent_completed");
72
+ this.logger.log(`[SubagentTracker] Subagent completed: ${toolUseId} (duration: ${this.getDuration(subagent)}ms)`);
73
+ }
74
+ /**
75
+ * Mark a subagent as failed
76
+ */
77
+ async failSubagent(toolUseId, error) {
78
+ const subagent = this.subagents.get(toolUseId);
79
+ if (!subagent) {
80
+ this.logger.error(`[SubagentTracker] Cannot fail unknown subagent: ${toolUseId}`);
81
+ return;
82
+ }
83
+ subagent.status = "failed";
84
+ subagent.completedAt = Date.now();
85
+ subagent.error = error;
86
+ await this.emitEvent("subagent_failed", subagent);
87
+ await this.sendSubagentNotification(subagent, "subagent_failed");
88
+ this.logger.error(`[SubagentTracker] Subagent failed: ${toolUseId} - ${error}`);
89
+ }
90
+ /**
91
+ * Mark a subagent as cancelled
92
+ */
93
+ async cancelSubagent(toolUseId) {
94
+ const subagent = this.subagents.get(toolUseId);
95
+ if (!subagent) {
96
+ return; // Silent fail for cancel - may not be tracked
97
+ }
98
+ subagent.status = "cancelled";
99
+ subagent.completedAt = Date.now();
100
+ await this.emitEvent("subagent_cancelled", subagent);
101
+ await this.sendSubagentNotification(subagent, "subagent_cancelled");
102
+ this.logger.log(`[SubagentTracker] Subagent cancelled: ${toolUseId}`);
103
+ }
104
+ /**
105
+ * Send progress update for a running subagent
106
+ */
107
+ async updateProgress(toolUseId, progressData) {
108
+ const subagent = this.subagents.get(toolUseId);
109
+ if (!subagent || subagent.status !== "running") {
110
+ return;
111
+ }
112
+ await this.emitEvent("subagent_progress", subagent, progressData);
113
+ await this.sendSubagentNotification(subagent, "subagent_progress");
114
+ }
115
+ /**
116
+ * Get a tracked subagent by ID
117
+ */
118
+ getSubagent(toolUseId) {
119
+ return this.subagents.get(toolUseId);
120
+ }
121
+ /**
122
+ * Get all subagents for a session
123
+ */
124
+ getSessionSubagents(sessionId) {
125
+ const ids = this.sessionSubagents.get(sessionId);
126
+ if (!ids)
127
+ return [];
128
+ return Array.from(ids)
129
+ .map((id) => this.subagents.get(id))
130
+ .filter((s) => s !== undefined);
131
+ }
132
+ /**
133
+ * Get all currently running subagents
134
+ */
135
+ getRunningSubagents() {
136
+ return Array.from(this.subagents.values()).filter((s) => s.status === "running");
137
+ }
138
+ /**
139
+ * Get all subagents (for debugging/monitoring)
140
+ */
141
+ getAllSubagents() {
142
+ return Array.from(this.subagents.values());
143
+ }
144
+ /**
145
+ * Check if a tool use ID is a Task tool (subagent)
146
+ */
147
+ isSubagent(toolUseId) {
148
+ return this.subagents.has(toolUseId);
149
+ }
150
+ /**
151
+ * Add event listener for subagent lifecycle events
152
+ */
153
+ addEventListener(event, listener) {
154
+ if (!this.listeners.has(event)) {
155
+ this.listeners.set(event, new Set());
156
+ }
157
+ this.listeners.get(event).add(listener);
158
+ }
159
+ /**
160
+ * Remove event listener
161
+ */
162
+ removeEventListener(event, listener) {
163
+ this.listeners.get(event)?.delete(listener);
164
+ }
165
+ /**
166
+ * Clean up completed subagents older than given age (in ms)
167
+ */
168
+ cleanup(maxAgeMs = 3600000) {
169
+ const now = Date.now();
170
+ let cleanedCount = 0;
171
+ for (const [id, subagent] of this.subagents) {
172
+ if ((subagent.status === "completed" ||
173
+ subagent.status === "failed" ||
174
+ subagent.status === "cancelled") &&
175
+ subagent.completedAt &&
176
+ now - subagent.completedAt > maxAgeMs) {
177
+ this.subagents.delete(id);
178
+ this.sessionSubagents.get(subagent.parentSessionId)?.delete(id);
179
+ cleanedCount++;
180
+ }
181
+ }
182
+ return cleanedCount;
183
+ }
184
+ /**
185
+ * Get statistics about subagents
186
+ */
187
+ getStats() {
188
+ const subagents = Array.from(this.subagents.values());
189
+ return {
190
+ total: subagents.length,
191
+ pending: subagents.filter((s) => s.status === "pending").length,
192
+ running: subagents.filter((s) => s.status === "running").length,
193
+ completed: subagents.filter((s) => s.status === "completed").length,
194
+ failed: subagents.filter((s) => s.status === "failed").length,
195
+ cancelled: subagents.filter((s) => s.status === "cancelled").length,
196
+ byType: this.countByType(subagents),
197
+ averageDurationMs: this.calculateAverageDuration(subagents),
198
+ };
199
+ }
200
+ /**
201
+ * Clear all tracked subagents (useful for testing)
202
+ */
203
+ clear() {
204
+ this.subagents.clear();
205
+ this.sessionSubagents.clear();
206
+ }
207
+ // Private helper methods
208
+ async emitEvent(event, subagent, data) {
209
+ const listeners = this.listeners.get(event);
210
+ if (!listeners)
211
+ return;
212
+ for (const listener of listeners) {
213
+ try {
214
+ await listener(subagent, data);
215
+ }
216
+ catch (err) {
217
+ this.logger.error(`[SubagentTracker] Error in event listener:`, err);
218
+ }
219
+ }
220
+ }
221
+ async sendSubagentNotification(subagent, eventType) {
222
+ if (!this.client)
223
+ return;
224
+ const notification = {
225
+ sessionId: subagent.parentSessionId,
226
+ update: {
227
+ sessionUpdate: "tool_call_update",
228
+ toolCallId: subagent.id,
229
+ _meta: {
230
+ claudeCode: {
231
+ subagent: {
232
+ id: subagent.id,
233
+ eventType,
234
+ subagentType: subagent.subagentType,
235
+ description: subagent.description,
236
+ status: subagent.status,
237
+ parentSessionId: subagent.parentSessionId,
238
+ parentToolUseId: subagent.parentToolUseId,
239
+ model: subagent.model,
240
+ runInBackground: subagent.runInBackground,
241
+ agentId: subagent.agentId,
242
+ durationMs: this.getDuration(subagent),
243
+ },
244
+ },
245
+ },
246
+ },
247
+ };
248
+ await this.client.sessionUpdate(notification);
249
+ }
250
+ getDuration(subagent) {
251
+ if (!subagent.startedAt)
252
+ return undefined;
253
+ const endTime = subagent.completedAt ?? Date.now();
254
+ return endTime - subagent.startedAt;
255
+ }
256
+ countByType(subagents) {
257
+ const counts = {};
258
+ for (const s of subagents) {
259
+ counts[s.subagentType] = (counts[s.subagentType] || 0) + 1;
260
+ }
261
+ return counts;
262
+ }
263
+ calculateAverageDuration(subagents) {
264
+ const completed = subagents.filter((s) => (s.status === "completed" || s.status === "failed") && s.startedAt && s.completedAt);
265
+ if (completed.length === 0)
266
+ return undefined;
267
+ const totalDuration = completed.reduce((sum, s) => sum + (s.completedAt - s.startedAt), 0);
268
+ return Math.round(totalDuration / completed.length);
269
+ }
270
+ }
271
+ /**
272
+ * Utility to check if a tool input is for the Task tool
273
+ */
274
+ export function isTaskToolInput(input) {
275
+ return (typeof input === "object" &&
276
+ input !== null &&
277
+ "prompt" in input &&
278
+ "subagent_type" in input &&
279
+ "description" in input);
280
+ }
281
+ /**
282
+ * Extract subagent metadata from Task tool input
283
+ */
284
+ export function extractSubagentMeta(input) {
285
+ return {
286
+ description: input.description,
287
+ subagentType: input.subagent_type,
288
+ model: input.model,
289
+ runInBackground: input.run_in_background ?? false,
290
+ maxTurns: input.max_turns,
291
+ };
292
+ }
@@ -0,0 +1,50 @@
1
+ import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk";
2
+ import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
3
+ export declare const ACP_TOOL_NAME_PREFIX = "mcp__acp__";
4
+ export declare const acpToolNames: {
5
+ read: string;
6
+ edit: string;
7
+ write: string;
8
+ bash: string;
9
+ killShell: string;
10
+ bashOutput: string;
11
+ };
12
+ export declare const EDIT_TOOL_NAMES: string[];
13
+ import { BetaBashCodeExecutionToolResultBlockParam, BetaCodeExecutionToolResultBlockParam, BetaRequestMCPToolResultBlockParam, BetaTextEditorCodeExecutionToolResultBlockParam, BetaToolSearchToolResultBlockParam, BetaWebFetchToolResultBlockParam, BetaWebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources/beta.mjs";
14
+ import { HookCallback } from "@anthropic-ai/claude-agent-sdk";
15
+ import { Logger } from "./acp-agent.js";
16
+ import { SettingsManager } from "./settings.js";
17
+ interface ToolInfo {
18
+ title: string;
19
+ kind: ToolKind;
20
+ content: ToolCallContent[];
21
+ locations?: ToolCallLocation[];
22
+ }
23
+ interface ToolUpdate {
24
+ title?: string;
25
+ content?: ToolCallContent[];
26
+ locations?: ToolCallLocation[];
27
+ }
28
+ export declare function toolInfoFromToolUse(toolUse: any): ToolInfo;
29
+ export declare function toolUpdateFromToolResult(toolResult: ToolResultBlockParam | BetaWebSearchToolResultBlockParam | BetaWebFetchToolResultBlockParam | WebSearchToolResultBlockParam | BetaCodeExecutionToolResultBlockParam | BetaBashCodeExecutionToolResultBlockParam | BetaTextEditorCodeExecutionToolResultBlockParam | BetaRequestMCPToolResultBlockParam | BetaToolSearchToolResultBlockParam, toolUse: any | undefined): ToolUpdate;
30
+ export type ClaudePlanEntry = {
31
+ content: string;
32
+ status: "pending" | "in_progress" | "completed";
33
+ activeForm: string;
34
+ };
35
+ export declare function planEntries(input: {
36
+ todos: ClaudePlanEntry[];
37
+ }): PlanEntry[];
38
+ export declare function markdownEscape(text: string): string;
39
+ export declare const registerHookCallback: (toolUseID: string, { onPostToolUseHook, }: {
40
+ onPostToolUseHook?: (toolUseID: string, toolInput: unknown, toolResponse: unknown) => Promise<void>;
41
+ }) => void;
42
+ export declare const createPostToolUseHook: (logger?: Logger) => HookCallback;
43
+ /**
44
+ * Creates a PreToolUse hook that checks permissions using the SettingsManager.
45
+ * This runs before the SDK's built-in permission rules, allowing us to enforce
46
+ * our own permission settings for ACP-prefixed tools.
47
+ */
48
+ export declare const createPreToolUseHook: (settingsManager: SettingsManager, logger?: Logger) => HookCallback;
49
+ export {};
50
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGlG,OAAO,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAWlG,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,YAAY;;;;;;;CAOxB,CAAC;AAEF,eAAO,MAAM,eAAe,UAA0C,CAAC;AAEvE,OAAO,EACL,yCAAyC,EACzC,qCAAqC,EACrC,kCAAkC,EAClC,+CAA+C,EAC/C,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,CA+V1D;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EACN,oBAAoB,GACpB,iCAAiC,GACjC,gCAAgC,GAChC,6BAA6B,GAC7B,qCAAqC,GACrC,yCAAyC,GACzC,+CAA+C,GAC/C,kCAAkC,GAClC,kCAAkC,EACtC,OAAO,EAAE,GAAG,GAAG,SAAS,GACvB,UAAU,CA4HZ;AAmCD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,SAAS,EAAE,CAM5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAcD,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,wBAEG;IACD,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,SAKF,CAAC;AAGF,eAAO,MAAM,qBAAqB,GAC/B,SAAQ,MAAgB,KAAG,YAa3B,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC9B,iBAAiB,eAAe,EAAE,SAAQ,MAAgB,KAAG,YA2C7D,CAAC"}