@hasna/todos 0.10.13 → 0.10.15
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.
- package/dist/cli/index.js +300 -0
- package/dist/lib/auto-assign.d.ts +18 -2
- package/dist/lib/auto-assign.d.ts.map +1 -1
- package/dist/mcp/index.js +6475 -6134
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -9817,6 +9817,161 @@ var init_zod = __esm(() => {
|
|
|
9817
9817
|
init_external();
|
|
9818
9818
|
});
|
|
9819
9819
|
|
|
9820
|
+
// src/lib/auto-assign.ts
|
|
9821
|
+
var exports_auto_assign = {};
|
|
9822
|
+
__export(exports_auto_assign, {
|
|
9823
|
+
findBestAgent: () => findBestAgent,
|
|
9824
|
+
autoAssignTask: () => autoAssignTask
|
|
9825
|
+
});
|
|
9826
|
+
function findBestAgent(_task, db) {
|
|
9827
|
+
const d = db || getDatabase();
|
|
9828
|
+
const agents = listAgents(d).filter((a) => (a.role || "agent") === "agent");
|
|
9829
|
+
if (agents.length === 0)
|
|
9830
|
+
return null;
|
|
9831
|
+
const inProgressTasks = listTasks({ status: "in_progress" }, d);
|
|
9832
|
+
const load = new Map;
|
|
9833
|
+
for (const a of agents)
|
|
9834
|
+
load.set(a.name, 0);
|
|
9835
|
+
for (const t of inProgressTasks) {
|
|
9836
|
+
const name = t.assigned_to || t.agent_id;
|
|
9837
|
+
if (name && load.has(name)) {
|
|
9838
|
+
load.set(name, (load.get(name) || 0) + 1);
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
let bestAgent = agents[0].name;
|
|
9842
|
+
let bestLoad = load.get(bestAgent) ?? 0;
|
|
9843
|
+
for (const a of agents) {
|
|
9844
|
+
const l = load.get(a.name) ?? 0;
|
|
9845
|
+
if (l < bestLoad) {
|
|
9846
|
+
bestAgent = a.name;
|
|
9847
|
+
bestLoad = l;
|
|
9848
|
+
}
|
|
9849
|
+
}
|
|
9850
|
+
return bestAgent;
|
|
9851
|
+
}
|
|
9852
|
+
function getAgentWorkloads(d) {
|
|
9853
|
+
const rows = d.query("SELECT assigned_to, COUNT(*) as count FROM tasks WHERE status = 'in_progress' AND assigned_to IS NOT NULL GROUP BY assigned_to").all();
|
|
9854
|
+
return new Map(rows.map((r) => [r.assigned_to, r.count]));
|
|
9855
|
+
}
|
|
9856
|
+
function buildPrompt(task, agents) {
|
|
9857
|
+
const agentList = agents.map((a) => `- ${a.name} (role: ${a.role}, caps: [${a.capabilities.join(", ")}], active_tasks: ${a.in_progress_tasks})`).join(`
|
|
9858
|
+
`);
|
|
9859
|
+
return `You are a task routing assistant. Given a task and available agents, choose the SINGLE best agent.
|
|
9860
|
+
|
|
9861
|
+
TASK:
|
|
9862
|
+
Title: ${task.title}
|
|
9863
|
+
Priority: ${task.priority}
|
|
9864
|
+
Tags: ${task.tags.join(", ") || "none"}
|
|
9865
|
+
Description: ${task.description?.slice(0, 300) || "none"}
|
|
9866
|
+
|
|
9867
|
+
AVAILABLE AGENTS:
|
|
9868
|
+
${agentList}
|
|
9869
|
+
|
|
9870
|
+
Rules:
|
|
9871
|
+
- Match task tags/content to agent capabilities
|
|
9872
|
+
- Prefer agents with fewer active tasks
|
|
9873
|
+
- Prefer agents whose role fits the task (lead for critical, developer for features, qa for testing)
|
|
9874
|
+
- If no clear match, pick the agent with fewest active tasks
|
|
9875
|
+
|
|
9876
|
+
Respond with ONLY a JSON object: {"agent_name": "<name>", "reason": "<one sentence>"}`;
|
|
9877
|
+
}
|
|
9878
|
+
async function callCerebras(prompt, apiKey) {
|
|
9879
|
+
try {
|
|
9880
|
+
const resp = await fetch(CEREBRAS_API_URL, {
|
|
9881
|
+
method: "POST",
|
|
9882
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
9883
|
+
body: JSON.stringify({
|
|
9884
|
+
model: CEREBRAS_MODEL,
|
|
9885
|
+
messages: [{ role: "user", content: prompt }],
|
|
9886
|
+
max_tokens: 150,
|
|
9887
|
+
temperature: 0
|
|
9888
|
+
}),
|
|
9889
|
+
signal: AbortSignal.timeout(1e4)
|
|
9890
|
+
});
|
|
9891
|
+
if (!resp.ok)
|
|
9892
|
+
return null;
|
|
9893
|
+
const data = await resp.json();
|
|
9894
|
+
const content = data?.choices?.[0]?.message?.content?.trim();
|
|
9895
|
+
if (!content)
|
|
9896
|
+
return null;
|
|
9897
|
+
const match = content.match(/\{[^}]+\}/s);
|
|
9898
|
+
if (!match)
|
|
9899
|
+
return null;
|
|
9900
|
+
return JSON.parse(match[0]);
|
|
9901
|
+
} catch {
|
|
9902
|
+
return null;
|
|
9903
|
+
}
|
|
9904
|
+
}
|
|
9905
|
+
async function autoAssignTask(taskId, db) {
|
|
9906
|
+
const d = db || getDatabase();
|
|
9907
|
+
const task = getTask(taskId, d);
|
|
9908
|
+
if (!task)
|
|
9909
|
+
throw new Error(`Task ${taskId} not found`);
|
|
9910
|
+
const agents = listAgents(d).filter((a) => a.status === "active");
|
|
9911
|
+
if (agents.length === 0) {
|
|
9912
|
+
return { task_id: taskId, assigned_to: null, agent_name: null, method: "no_agents" };
|
|
9913
|
+
}
|
|
9914
|
+
const workloads = getAgentWorkloads(d);
|
|
9915
|
+
const apiKey = process.env["CEREBRAS_API_KEY"];
|
|
9916
|
+
let selectedAgent = null;
|
|
9917
|
+
let method = "capability_match";
|
|
9918
|
+
let reason;
|
|
9919
|
+
if (apiKey) {
|
|
9920
|
+
const agentData = agents.map((a) => ({
|
|
9921
|
+
id: a.id,
|
|
9922
|
+
name: a.name,
|
|
9923
|
+
role: a.role || "agent",
|
|
9924
|
+
capabilities: a.capabilities || [],
|
|
9925
|
+
in_progress_tasks: workloads.get(a.id) ?? 0
|
|
9926
|
+
}));
|
|
9927
|
+
const result = await callCerebras(buildPrompt({
|
|
9928
|
+
title: task.title,
|
|
9929
|
+
description: task.description,
|
|
9930
|
+
priority: task.priority,
|
|
9931
|
+
tags: task.tags || []
|
|
9932
|
+
}, agentData), apiKey);
|
|
9933
|
+
if (result?.agent_name) {
|
|
9934
|
+
selectedAgent = agents.find((a) => a.name === result.agent_name) ?? null;
|
|
9935
|
+
if (selectedAgent) {
|
|
9936
|
+
method = "cerebras";
|
|
9937
|
+
reason = result.reason;
|
|
9938
|
+
}
|
|
9939
|
+
}
|
|
9940
|
+
}
|
|
9941
|
+
if (!selectedAgent) {
|
|
9942
|
+
const taskTags = task.tags || [];
|
|
9943
|
+
const capable = getCapableAgents(taskTags, { min_score: 0, limit: 10 }, d);
|
|
9944
|
+
if (capable.length > 0) {
|
|
9945
|
+
const sorted = capable.sort((a, b) => {
|
|
9946
|
+
if (b.score !== a.score)
|
|
9947
|
+
return b.score - a.score;
|
|
9948
|
+
return (workloads.get(a.agent.id) ?? 0) - (workloads.get(b.agent.id) ?? 0);
|
|
9949
|
+
});
|
|
9950
|
+
selectedAgent = sorted[0].agent;
|
|
9951
|
+
reason = `Capability match (score: ${sorted[0].score.toFixed(2)})`;
|
|
9952
|
+
} else {
|
|
9953
|
+
selectedAgent = agents.slice().sort((a, b) => (workloads.get(a.id) ?? 0) - (workloads.get(b.id) ?? 0))[0];
|
|
9954
|
+
reason = `Least busy agent (${workloads.get(selectedAgent.id) ?? 0} active tasks)`;
|
|
9955
|
+
}
|
|
9956
|
+
}
|
|
9957
|
+
if (selectedAgent) {
|
|
9958
|
+
updateTask(taskId, { assigned_to: selectedAgent.id, version: task.version }, d);
|
|
9959
|
+
}
|
|
9960
|
+
return {
|
|
9961
|
+
task_id: taskId,
|
|
9962
|
+
assigned_to: selectedAgent?.id ?? null,
|
|
9963
|
+
agent_name: selectedAgent?.name ?? null,
|
|
9964
|
+
method,
|
|
9965
|
+
reason
|
|
9966
|
+
};
|
|
9967
|
+
}
|
|
9968
|
+
var CEREBRAS_API_URL = "https://api.cerebras.ai/v1/chat/completions", CEREBRAS_MODEL = "llama-3.3-70b";
|
|
9969
|
+
var init_auto_assign = __esm(() => {
|
|
9970
|
+
init_database();
|
|
9971
|
+
init_tasks();
|
|
9972
|
+
init_agents();
|
|
9973
|
+
});
|
|
9974
|
+
|
|
9820
9975
|
// src/db/task-files.ts
|
|
9821
9976
|
var exports_task_files = {};
|
|
9822
9977
|
__export(exports_task_files, {
|
|
@@ -13083,6 +13238,108 @@ Claimed: ${formatTask(result.claimed)}`);
|
|
|
13083
13238
|
}
|
|
13084
13239
|
});
|
|
13085
13240
|
}
|
|
13241
|
+
if (shouldRegisterTool("create_failure_task")) {
|
|
13242
|
+
server.tool("create_failure_task", "Create a task from a test/build/typecheck failure. Auto-assigns to the most likely agent based on file ownership and org chart.", {
|
|
13243
|
+
failure_type: exports_external.enum(["test", "build", "typecheck", "runtime", "other"]).describe("Type of failure"),
|
|
13244
|
+
title: exports_external.string().optional().describe("Task title (auto-generated from error if omitted)"),
|
|
13245
|
+
error_message: exports_external.string().describe("The error message or summary"),
|
|
13246
|
+
file_path: exports_external.string().optional().describe("File where the failure occurred"),
|
|
13247
|
+
stack_trace: exports_external.string().optional().describe("Stack trace or detailed output (truncated to 2000 chars)"),
|
|
13248
|
+
project_id: exports_external.string().optional().describe("Project to associate the task with"),
|
|
13249
|
+
priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default: high for build/typecheck, medium for test")
|
|
13250
|
+
}, async ({ failure_type, title, error_message, file_path, stack_trace, project_id, priority }) => {
|
|
13251
|
+
try {
|
|
13252
|
+
const { createTask: createTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
13253
|
+
const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
|
|
13254
|
+
const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
|
|
13255
|
+
const defaultPriority = failure_type === "build" || failure_type === "typecheck" ? "high" : "medium";
|
|
13256
|
+
const taskPriority = priority ?? defaultPriority;
|
|
13257
|
+
const autoTitle = title || `${failure_type.toUpperCase()} failure${file_path ? ` in ${file_path.split("/").pop()}` : ""}: ${error_message.slice(0, 60)}`;
|
|
13258
|
+
const description = [
|
|
13259
|
+
`**Failure type:** ${failure_type}`,
|
|
13260
|
+
file_path ? `**File:** ${file_path}` : null,
|
|
13261
|
+
`**Error:**
|
|
13262
|
+
\`\`\`
|
|
13263
|
+
${error_message.slice(0, 500)}
|
|
13264
|
+
\`\`\``,
|
|
13265
|
+
stack_trace ? `**Stack trace:**
|
|
13266
|
+
\`\`\`
|
|
13267
|
+
${stack_trace.slice(0, 1500)}
|
|
13268
|
+
\`\`\`` : null
|
|
13269
|
+
].filter(Boolean).join(`
|
|
13270
|
+
|
|
13271
|
+
`);
|
|
13272
|
+
const task = createTask2({
|
|
13273
|
+
title: autoTitle,
|
|
13274
|
+
description,
|
|
13275
|
+
priority: taskPriority,
|
|
13276
|
+
project_id: resolvedProjectId,
|
|
13277
|
+
tags: ["failure", failure_type, "auto-created"],
|
|
13278
|
+
status: "pending"
|
|
13279
|
+
});
|
|
13280
|
+
const assignResult = await autoAssignTask2(task.id);
|
|
13281
|
+
return {
|
|
13282
|
+
content: [{
|
|
13283
|
+
type: "text",
|
|
13284
|
+
text: JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, assign_method: assignResult.method }, null, 2)
|
|
13285
|
+
}]
|
|
13286
|
+
};
|
|
13287
|
+
} catch (e) {
|
|
13288
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13289
|
+
}
|
|
13290
|
+
});
|
|
13291
|
+
}
|
|
13292
|
+
if (shouldRegisterTool("auto_assign_task")) {
|
|
13293
|
+
server.tool("auto_assign_task", "Auto-assign a task to the best available agent. Uses Cerebras LLM (llama-3.3-70b) if CEREBRAS_API_KEY is set, otherwise falls back to capability-based matching.", {
|
|
13294
|
+
task_id: exports_external.string().describe("Task to auto-assign")
|
|
13295
|
+
}, async ({ task_id }) => {
|
|
13296
|
+
try {
|
|
13297
|
+
const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
|
|
13298
|
+
const resolvedId = resolveId(task_id);
|
|
13299
|
+
const result = await autoAssignTask2(resolvedId);
|
|
13300
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
13301
|
+
} catch (e) {
|
|
13302
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13303
|
+
}
|
|
13304
|
+
});
|
|
13305
|
+
}
|
|
13306
|
+
if (shouldRegisterTool("auto_assign_unassigned")) {
|
|
13307
|
+
server.tool("auto_assign_unassigned", "Auto-assign all unassigned pending tasks in a project using Cerebras LLM routing. Returns summary of assignments made.", {
|
|
13308
|
+
project_id: exports_external.string().optional().describe("Filter to a specific project"),
|
|
13309
|
+
limit: exports_external.number().optional().describe("Max tasks to assign (default: 20)")
|
|
13310
|
+
}, async ({ project_id, limit }) => {
|
|
13311
|
+
try {
|
|
13312
|
+
const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
|
|
13313
|
+
const { listTasks: listTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
13314
|
+
const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
|
|
13315
|
+
const tasks = listTasks2({
|
|
13316
|
+
status: "pending",
|
|
13317
|
+
project_id: resolvedProjectId
|
|
13318
|
+
}).tasks.filter((t) => !t.assigned_to).slice(0, limit ?? 20);
|
|
13319
|
+
const results = [];
|
|
13320
|
+
for (const task of tasks) {
|
|
13321
|
+
try {
|
|
13322
|
+
const r = await autoAssignTask2(task.id);
|
|
13323
|
+
results.push(r);
|
|
13324
|
+
} catch {}
|
|
13325
|
+
}
|
|
13326
|
+
const assigned = results.filter((r) => r.assigned_to);
|
|
13327
|
+
return {
|
|
13328
|
+
content: [{
|
|
13329
|
+
type: "text",
|
|
13330
|
+
text: JSON.stringify({
|
|
13331
|
+
total_checked: tasks.length,
|
|
13332
|
+
assigned: assigned.length,
|
|
13333
|
+
skipped: tasks.length - assigned.length,
|
|
13334
|
+
results
|
|
13335
|
+
}, null, 2)
|
|
13336
|
+
}]
|
|
13337
|
+
};
|
|
13338
|
+
} catch (e) {
|
|
13339
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13340
|
+
}
|
|
13341
|
+
});
|
|
13342
|
+
}
|
|
13086
13343
|
if (shouldRegisterTool("search_tools")) {
|
|
13087
13344
|
server.tool("search_tools", "List all tool names, optionally filtered by substring.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
13088
13345
|
const all = [
|
|
@@ -18727,6 +18984,49 @@ program2.command("context").description("Session start context: status, latest h
|
|
|
18727
18984
|
console.log(chalk.dim(`
|
|
18728
18985
|
as_of: ${new Date().toISOString()}`));
|
|
18729
18986
|
});
|
|
18987
|
+
program2.command("report-failure").description("Create a task from a test/build/typecheck failure and auto-assign it").requiredOption("--error <message>", "Error message or summary").option("--type <type>", "Failure type: test, build, typecheck, runtime, other", "test").option("--file <path>", "File where failure occurred").option("--stack <trace>", "Stack trace or detailed output").option("--title <title>", "Custom task title (auto-generated if omitted)").option("--priority <p>", "Priority: low, medium, high, critical").option("--json", "Output as JSON").action(async (opts) => {
|
|
18988
|
+
const globalOpts = program2.opts();
|
|
18989
|
+
const { createTask: createTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
18990
|
+
const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
|
|
18991
|
+
const projectId = autoProject(globalOpts);
|
|
18992
|
+
const failureType = opts.type || "test";
|
|
18993
|
+
const defaultPriority = failureType === "build" || failureType === "typecheck" ? "high" : "medium";
|
|
18994
|
+
const taskPriority = opts.priority || defaultPriority;
|
|
18995
|
+
const autoTitle = opts.title || `${failureType.toUpperCase()} failure${opts.file ? ` in ${opts.file.split("/").pop()}` : ""}: ${opts.error.slice(0, 60)}`;
|
|
18996
|
+
const descParts = [
|
|
18997
|
+
`**Failure type:** ${failureType}`,
|
|
18998
|
+
opts.file ? `**File:** ${opts.file}` : null,
|
|
18999
|
+
`**Error:**
|
|
19000
|
+
\`\`\`
|
|
19001
|
+
${opts.error.slice(0, 500)}
|
|
19002
|
+
\`\`\``,
|
|
19003
|
+
opts.stack ? `**Stack trace:**
|
|
19004
|
+
\`\`\`
|
|
19005
|
+
${opts.stack.slice(0, 1500)}
|
|
19006
|
+
\`\`\`` : null
|
|
19007
|
+
].filter(Boolean).join(`
|
|
19008
|
+
|
|
19009
|
+
`);
|
|
19010
|
+
const task = createTask2({
|
|
19011
|
+
title: autoTitle,
|
|
19012
|
+
description: descParts,
|
|
19013
|
+
priority: taskPriority,
|
|
19014
|
+
project_id: projectId || undefined,
|
|
19015
|
+
tags: ["failure", failureType, "auto-created"],
|
|
19016
|
+
status: "pending"
|
|
19017
|
+
});
|
|
19018
|
+
const assignResult = await autoAssignTask2(task.id);
|
|
19019
|
+
if (opts.json || globalOpts.json) {
|
|
19020
|
+
console.log(JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, method: assignResult.method }));
|
|
19021
|
+
return;
|
|
19022
|
+
}
|
|
19023
|
+
console.log(chalk.green(`\u2713 Created task ${task.short_id || task.id.slice(0, 8)}: ${task.title}`));
|
|
19024
|
+
if (assignResult.agent_name) {
|
|
19025
|
+
console.log(chalk.cyan(` Assigned to: ${assignResult.agent_name} (via ${assignResult.method})`));
|
|
19026
|
+
if (assignResult.reason)
|
|
19027
|
+
console.log(chalk.dim(` Reason: ${assignResult.reason}`));
|
|
19028
|
+
}
|
|
19029
|
+
});
|
|
18730
19030
|
program2.action(async () => {
|
|
18731
19031
|
if (process.stdout.isTTY) {
|
|
18732
19032
|
try {
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-assign tasks to agents using Cerebras LLM for intelligent routing.
|
|
3
|
+
* Falls back to capability-based matching when the API key is unavailable or the call fails.
|
|
4
|
+
*/
|
|
1
5
|
import type { Database } from "bun:sqlite";
|
|
2
6
|
import type { Task } from "../types/index.js";
|
|
7
|
+
export interface AutoAssignResult {
|
|
8
|
+
task_id: string;
|
|
9
|
+
assigned_to: string | null;
|
|
10
|
+
agent_name: string | null;
|
|
11
|
+
method: "cerebras" | "capability_match" | "no_agents";
|
|
12
|
+
reason?: string;
|
|
13
|
+
}
|
|
3
14
|
/**
|
|
4
|
-
* Find the best agent to assign a task to.
|
|
15
|
+
* Find the best agent to assign a task to (legacy simple version, no I/O).
|
|
5
16
|
* Strategy: least-loaded agent with role "agent" (not admin/observer).
|
|
6
|
-
* Returns agent name or null if no agents available.
|
|
7
17
|
*/
|
|
8
18
|
export declare function findBestAgent(_task: Task, db?: Database): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Auto-assign a task to the best available agent.
|
|
21
|
+
* Uses Cerebras LLM (llama-3.3-70b) if CEREBRAS_API_KEY is set,
|
|
22
|
+
* otherwise falls back to capability-based matching.
|
|
23
|
+
*/
|
|
24
|
+
export declare function autoAssignTask(taskId: string, db?: Database): Promise<AutoAssignResult>;
|
|
9
25
|
//# sourceMappingURL=auto-assign.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-assign.d.ts","sourceRoot":"","sources":["../../src/lib/auto-assign.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"auto-assign.d.ts","sourceRoot":"","sources":["../../src/lib/auto-assign.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAK9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,UAAU,GAAG,kBAAkB,GAAG,WAAW,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAsBvE;AA8DD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8D7F"}
|