@thoughtflow/core 0.2.1 → 0.3.1
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/README.md +284 -225
- package/dist/adapters/llm/openai.adapter.js +4 -4
- package/dist/adapters/llm/openai.adapter.js.map +1 -1
- package/dist/bin/mcp-server.d.ts +18 -0
- package/dist/bin/mcp-server.d.ts.map +1 -0
- package/dist/bin/mcp-server.js +272 -0
- package/dist/bin/mcp-server.js.map +1 -0
- package/dist/contracts/mcp.types.d.ts +8 -1
- package/dist/contracts/mcp.types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/libs/mcp/mcp-llm-caller.class.d.ts +35 -0
- package/dist/libs/mcp/mcp-llm-caller.class.d.ts.map +1 -0
- package/dist/libs/mcp/mcp-llm-caller.class.js +31 -0
- package/dist/libs/mcp/mcp-llm-caller.class.js.map +1 -0
- package/dist/libs/mcp/mcp-server.class.d.ts +5 -5
- package/dist/libs/mcp/mcp-server.class.d.ts.map +1 -1
- package/dist/libs/mcp/mcp-server.class.js +52 -106
- package/dist/libs/mcp/mcp-server.class.js.map +1 -1
- package/dist/libs/mcp/mcp-tool-registry.class.js +1 -1
- package/dist/libs/mcp/mcp-tool-registry.class.js.map +1 -1
- package/dist/libs/mcp/vision-adapter-resolver.d.ts +15 -0
- package/dist/libs/mcp/vision-adapter-resolver.d.ts.map +1 -0
- package/dist/libs/mcp/vision-adapter-resolver.js +48 -0
- package/dist/libs/mcp/vision-adapter-resolver.js.map +1 -0
- package/dist/tools/mcp/tool-search.tool.d.ts +35 -0
- package/dist/tools/mcp/tool-search.tool.d.ts.map +1 -0
- package/dist/tools/mcp/tool-search.tool.js +186 -0
- package/dist/tools/mcp/tool-search.tool.js.map +1 -0
- package/dist/tools/workspace/browser-session-pool.d.ts +88 -0
- package/dist/tools/workspace/browser-session-pool.d.ts.map +1 -0
- package/dist/tools/workspace/browser-session-pool.js +302 -0
- package/dist/tools/workspace/browser-session-pool.js.map +1 -0
- package/package.json +5 -1
- package/skills/thoughtflow-mcp/SKILL.md +294 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ToolBase } from "../base/tool-base.class";
|
|
2
|
+
import { ToolContext, ToolExecutionResult } from "../../contracts";
|
|
3
|
+
import type { McpToolDefinition } from "../../contracts/mcp.types";
|
|
4
|
+
/**
|
|
5
|
+
* ToolSearchTool — discover tools by describing what you want to do.
|
|
6
|
+
*
|
|
7
|
+
* Instead of scanning a massive flat tool list, call this tool with a natural-language
|
|
8
|
+
* description of your task. It returns matching tools with their full input schemas
|
|
9
|
+
* so you know exactly what parameters to pass.
|
|
10
|
+
*
|
|
11
|
+
* This is the primary tool discovery mechanism when the MCP server runs in
|
|
12
|
+
* "compressed" tool list mode — the tool list only shows names + one-liners,
|
|
13
|
+
* and you use tool_search to get full schemas on demand.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ToolSearchTool extends ToolBase {
|
|
16
|
+
readonly name = "tool_search";
|
|
17
|
+
readonly description: string;
|
|
18
|
+
readonly namespace = "mcp";
|
|
19
|
+
readonly tags: string[];
|
|
20
|
+
readonly readonly = true;
|
|
21
|
+
readonly priority = 100;
|
|
22
|
+
private discovery;
|
|
23
|
+
private toolDefinitions;
|
|
24
|
+
constructor();
|
|
25
|
+
/**
|
|
26
|
+
* Set the tool definitions from the MCP server so we can return full schemas.
|
|
27
|
+
* Called by McpServer after initialization.
|
|
28
|
+
*/
|
|
29
|
+
setToolDefinitions(defs: McpToolDefinition[]): void;
|
|
30
|
+
run(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolExecutionResult>;
|
|
31
|
+
private searchByDomain;
|
|
32
|
+
private searchByIntent;
|
|
33
|
+
private formatResults;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=tool-search.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-search.tool.d.ts","sourceRoot":"","sources":["../../../packages/core/src/tools/mcp/tool-search.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAInE;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,WAAW,SAMwB;IAC5C,QAAQ,CAAC,SAAS,SAAS;IAC3B,QAAQ,CAAC,IAAI,WAAkC;IAC/C,QAAQ,CAAC,QAAQ,QAAQ;IACzB,QAAQ,CAAC,QAAQ,OAAO;IAExB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,eAAe,CAA2B;;IAgBlD;;;OAGG;IACH,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAI7C,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwC1F,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,cAAc;IAyDtB,OAAO,CAAC,aAAa;CAoCtB"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToolSearchTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const tool_base_class_1 = require("../base/tool-base.class");
|
|
6
|
+
const tool_discovery_class_1 = require("../../libs/tool-discovery.class");
|
|
7
|
+
const tool_router_class_1 = require("../../libs/tool-router.class");
|
|
8
|
+
/**
|
|
9
|
+
* ToolSearchTool — discover tools by describing what you want to do.
|
|
10
|
+
*
|
|
11
|
+
* Instead of scanning a massive flat tool list, call this tool with a natural-language
|
|
12
|
+
* description of your task. It returns matching tools with their full input schemas
|
|
13
|
+
* so you know exactly what parameters to pass.
|
|
14
|
+
*
|
|
15
|
+
* This is the primary tool discovery mechanism when the MCP server runs in
|
|
16
|
+
* "compressed" tool list mode — the tool list only shows names + one-liners,
|
|
17
|
+
* and you use tool_search to get full schemas on demand.
|
|
18
|
+
*/
|
|
19
|
+
class ToolSearchTool extends tool_base_class_1.ToolBase {
|
|
20
|
+
name = "tool_search";
|
|
21
|
+
description = "Discover available tools by describing what you want to do. " +
|
|
22
|
+
"Returns matching tools with their full input schemas (parameter names, types, descriptions). " +
|
|
23
|
+
"ALWAYS call this before using an unfamiliar tool — the compressed tool list only " +
|
|
24
|
+
"shows names and brief descriptions, not the required input format. " +
|
|
25
|
+
"Examples: 'read files', 'search codebase', 'run terminal commands', 'refactor TypeScript', " +
|
|
26
|
+
"'generate tests', 'check code quality'.";
|
|
27
|
+
namespace = "mcp";
|
|
28
|
+
tags = ["discover", "search", "help"];
|
|
29
|
+
readonly = true;
|
|
30
|
+
priority = 100; // Always high priority — LLM should see this first
|
|
31
|
+
discovery;
|
|
32
|
+
toolDefinitions = [];
|
|
33
|
+
constructor() {
|
|
34
|
+
super(zod_1.z.object({
|
|
35
|
+
query: zod_1.z.string().describe("Natural language description of what you want to do. " +
|
|
36
|
+
"Be specific: 'read a text file', 'search for functions by name', " +
|
|
37
|
+
"'run a shell command', 'analyze code complexity'. " +
|
|
38
|
+
"You can also search by domain: 'workspace tools', 'testing tools'."),
|
|
39
|
+
}));
|
|
40
|
+
this.discovery = new tool_discovery_class_1.ToolDiscoveryService(new tool_router_class_1.ToolCapabilityRouter());
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the tool definitions from the MCP server so we can return full schemas.
|
|
44
|
+
* Called by McpServer after initialization.
|
|
45
|
+
*/
|
|
46
|
+
setToolDefinitions(defs) {
|
|
47
|
+
this.toolDefinitions = defs;
|
|
48
|
+
}
|
|
49
|
+
async run(input, _ctx) {
|
|
50
|
+
const query = input["query"];
|
|
51
|
+
if (!query)
|
|
52
|
+
return { success: false, error: "query is required" };
|
|
53
|
+
// Check if query is a domain name
|
|
54
|
+
const domainMap = {
|
|
55
|
+
"workspace": "workspace",
|
|
56
|
+
"workspace tools": "workspace",
|
|
57
|
+
"codebase": "codebase",
|
|
58
|
+
"codebase tools": "codebase",
|
|
59
|
+
"neural": "neural",
|
|
60
|
+
"neural tools": "neural",
|
|
61
|
+
"planning": "planning",
|
|
62
|
+
"planning tools": "planning",
|
|
63
|
+
"testing": "testing",
|
|
64
|
+
"testing tools": "testing",
|
|
65
|
+
"refactor": "refactor",
|
|
66
|
+
"refactor tools": "refactor",
|
|
67
|
+
"quality": "quality",
|
|
68
|
+
"quality tools": "quality",
|
|
69
|
+
"docs": "docs",
|
|
70
|
+
"documentation": "docs",
|
|
71
|
+
"devops": "devops",
|
|
72
|
+
"devops tools": "devops",
|
|
73
|
+
"database": "database",
|
|
74
|
+
"database tools": "database",
|
|
75
|
+
"memory": "memory",
|
|
76
|
+
"memory tools": "memory",
|
|
77
|
+
"conversation": "conversation",
|
|
78
|
+
"subagent": "subagent",
|
|
79
|
+
};
|
|
80
|
+
const domainQuery = domainMap[query.toLowerCase().trim()];
|
|
81
|
+
if (domainQuery) {
|
|
82
|
+
return this.searchByDomain(domainQuery);
|
|
83
|
+
}
|
|
84
|
+
return this.searchByIntent(query);
|
|
85
|
+
}
|
|
86
|
+
searchByDomain(domain) {
|
|
87
|
+
const defs = this.toolDefinitions.filter((d) => {
|
|
88
|
+
// Match tools whose names suggest they belong to this domain
|
|
89
|
+
// (we don't have direct category info in McpToolDefinition, so match by naming conventions)
|
|
90
|
+
const name = d.name.toLowerCase();
|
|
91
|
+
return name.includes(domain.toLowerCase().replace(/ tools$/, ""));
|
|
92
|
+
});
|
|
93
|
+
if (defs.length === 0) {
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
output: `No tools found for domain "${domain}". Available domains: workspace, codebase, neural, planning, testing, refactor, quality, docs, devops, database, memory, conversation, subagent.`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return this.formatResults(defs, `Domain: ${domain}`);
|
|
100
|
+
}
|
|
101
|
+
searchByIntent(query) {
|
|
102
|
+
const lower = query.toLowerCase();
|
|
103
|
+
// Score each tool definition by keyword match
|
|
104
|
+
const scored = this.toolDefinitions
|
|
105
|
+
.map((def) => {
|
|
106
|
+
let score = 0;
|
|
107
|
+
const text = `${def.name} ${def.description}`.toLowerCase();
|
|
108
|
+
// Name match is strongest
|
|
109
|
+
if (text.includes(lower))
|
|
110
|
+
score += 10;
|
|
111
|
+
if (def.name.toLowerCase().includes(lower.replace(/\s+/g, "")))
|
|
112
|
+
score += 8;
|
|
113
|
+
// Keyword matches
|
|
114
|
+
const keywords = lower.split(/\s+/);
|
|
115
|
+
for (const kw of keywords) {
|
|
116
|
+
if (kw.length < 3)
|
|
117
|
+
continue; // Skip short words
|
|
118
|
+
if (text.includes(kw))
|
|
119
|
+
score += 1;
|
|
120
|
+
}
|
|
121
|
+
return { def, score };
|
|
122
|
+
})
|
|
123
|
+
.filter((s) => s.score > 0)
|
|
124
|
+
.sort((a, b) => b.score - a.score)
|
|
125
|
+
.slice(0, 12);
|
|
126
|
+
if (scored.length === 0) {
|
|
127
|
+
// Fallback: use the discovery service
|
|
128
|
+
const searchResult = this.discovery.searchTools(query);
|
|
129
|
+
if (searchResult.startsWith("No tools found")) {
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
output: `No tools found for "${query}". Try a broader query, or search by domain: "workspace tools", "testing tools", "codebase tools", etc.\n\nAll domains: ${this.discovery["buildDomainSummary"]()}`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Cross-reference with our definitions
|
|
136
|
+
const foundNames = searchResult
|
|
137
|
+
.split("\n")
|
|
138
|
+
.map((line) => {
|
|
139
|
+
const match = line.match(/\*\*(\w+)\*\*/);
|
|
140
|
+
return match ? match[1] : null;
|
|
141
|
+
})
|
|
142
|
+
.filter(Boolean);
|
|
143
|
+
const matched = this.toolDefinitions.filter((d) => foundNames.includes(d.name));
|
|
144
|
+
if (matched.length > 0) {
|
|
145
|
+
return this.formatResults(matched, `Intent: ${query}`);
|
|
146
|
+
}
|
|
147
|
+
return { success: true, output: searchResult };
|
|
148
|
+
}
|
|
149
|
+
return this.formatResults(scored.map((s) => s.def), `Intent: ${query}`);
|
|
150
|
+
}
|
|
151
|
+
formatResults(defs, context) {
|
|
152
|
+
const lines = [
|
|
153
|
+
`## Tool Search Results — ${context}`,
|
|
154
|
+
`Found ${defs.length} matching tool(s):`,
|
|
155
|
+
"",
|
|
156
|
+
];
|
|
157
|
+
for (const def of defs) {
|
|
158
|
+
lines.push(`### ${def.name}`);
|
|
159
|
+
lines.push(`**Description:** ${def.description}`);
|
|
160
|
+
lines.push("");
|
|
161
|
+
// Full input schema
|
|
162
|
+
if (def.inputSchema && def.inputSchema.properties) {
|
|
163
|
+
lines.push("**Parameters:**");
|
|
164
|
+
const props = def.inputSchema.properties;
|
|
165
|
+
const required = def.inputSchema.required ?? [];
|
|
166
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
167
|
+
const isReq = required.includes(key) ? " (required)" : " (optional)";
|
|
168
|
+
const typeStr = prop.type ?? "string";
|
|
169
|
+
const desc = prop.description ? ` — ${prop.description}` : "";
|
|
170
|
+
const enumStr = prop.enum ? ` [${prop.enum.join(" | ")}]` : "";
|
|
171
|
+
lines.push(` - \`${key}\`: ${typeStr}${enumStr}${isReq}${desc}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
lines.push("**Parameters:** (no schema — accepts any input)");
|
|
176
|
+
}
|
|
177
|
+
lines.push("");
|
|
178
|
+
}
|
|
179
|
+
lines.push("---");
|
|
180
|
+
lines.push("**Next step:** call the tool with the parameters shown above.");
|
|
181
|
+
lines.push('Example: `{"name": "<tool_name>", "arguments": {"<param>": "<value>"}}`');
|
|
182
|
+
return { success: true, output: lines.join("\n") };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.ToolSearchTool = ToolSearchTool;
|
|
186
|
+
//# sourceMappingURL=tool-search.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-search.tool.js","sourceRoot":"","sources":["../../../packages/core/src/tools/mcp/tool-search.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrowserSessionPool — manages multiple headless browser sessions with
|
|
3
|
+
* isolated pages, console logs, and network activity per session.
|
|
4
|
+
*
|
|
5
|
+
* Auto-cleans up sessions after 5 minutes of inactivity.
|
|
6
|
+
*/
|
|
7
|
+
interface ConsoleEntry {
|
|
8
|
+
type: string;
|
|
9
|
+
text: string;
|
|
10
|
+
location: string;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
}
|
|
13
|
+
interface NetworkEntry {
|
|
14
|
+
idx: number;
|
|
15
|
+
method: string;
|
|
16
|
+
url: string;
|
|
17
|
+
status?: number;
|
|
18
|
+
statusText?: string;
|
|
19
|
+
duration?: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
reqHeaders?: Record<string, string>;
|
|
22
|
+
reqBody?: string;
|
|
23
|
+
resHeaders?: Record<string, string>;
|
|
24
|
+
resBody?: string;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class BrowserSessionPool {
|
|
28
|
+
private sessions;
|
|
29
|
+
private cleanupTimer;
|
|
30
|
+
/** Create or retrieve a session. If sessionId is empty, creates a new one. */
|
|
31
|
+
getOrCreate(sessionId?: string): Promise<{
|
|
32
|
+
sessionId: string;
|
|
33
|
+
page: import("playwright").Page;
|
|
34
|
+
}>;
|
|
35
|
+
/** Navigate the active page of a session. */
|
|
36
|
+
getPage(sessionId: string): Promise<import("playwright").Page | null>;
|
|
37
|
+
/** Open a new tab in an existing session. */
|
|
38
|
+
newPage(sessionId: string): Promise<{
|
|
39
|
+
sessionId: string;
|
|
40
|
+
page: import("playwright").Page;
|
|
41
|
+
}>;
|
|
42
|
+
/** Switch active tab. */
|
|
43
|
+
switchPage(sessionId: string, pageId: string): boolean;
|
|
44
|
+
/** Close a tab (or the active one if pageId omitted). */
|
|
45
|
+
closePage(sessionId: string, pageId?: string): Promise<boolean>;
|
|
46
|
+
/** Destroy a session completely. */
|
|
47
|
+
destroy(sessionId: string): Promise<void>;
|
|
48
|
+
/** Destroy all sessions. */
|
|
49
|
+
destroyAll(): Promise<number>;
|
|
50
|
+
/** Set the initial navigation URL for a session. */
|
|
51
|
+
setInitUrl(sessionId: string, url: string): void;
|
|
52
|
+
/** List all active sessions with metadata. */
|
|
53
|
+
list(): Array<{
|
|
54
|
+
sessionId: string;
|
|
55
|
+
initUrl: string;
|
|
56
|
+
currentUrl: string;
|
|
57
|
+
pageCount: number;
|
|
58
|
+
activePageId: string;
|
|
59
|
+
createdAt: number;
|
|
60
|
+
lastActivity: number;
|
|
61
|
+
status: "active" | "idle";
|
|
62
|
+
}>;
|
|
63
|
+
/** Get console logs for active page. */
|
|
64
|
+
getConsole(sessionId: string): ConsoleEntry[];
|
|
65
|
+
/** Get network entries for active page. */
|
|
66
|
+
getNetwork(sessionId: string): NetworkEntry[];
|
|
67
|
+
/** Clear console logs for active page. */
|
|
68
|
+
clearConsole(sessionId: string): void;
|
|
69
|
+
/** Clear network entries for active page. */
|
|
70
|
+
clearNetwork(sessionId: string): void;
|
|
71
|
+
/** Cache a screenshot base64 string for the session. */
|
|
72
|
+
cacheScreenshot(sessionId: string, base64: string): void;
|
|
73
|
+
/** Get cached screenshot base64 string. */
|
|
74
|
+
getCachedScreenshot(sessionId: string): string | null;
|
|
75
|
+
/** List all open tabs in a session. */
|
|
76
|
+
listPages(sessionId: string): Array<{
|
|
77
|
+
id: string;
|
|
78
|
+
url: string;
|
|
79
|
+
title: string;
|
|
80
|
+
}>;
|
|
81
|
+
private getActivePageData;
|
|
82
|
+
private attachListeners;
|
|
83
|
+
private startCleanup;
|
|
84
|
+
}
|
|
85
|
+
/** Singleton instance */
|
|
86
|
+
export declare const browserPool: BrowserSessionPool;
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=browser-session-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-session-pool.d.ts","sourceRoot":"","sources":["../../../src/tools/workspace/browser-session-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BrowserSessionPool — manages multiple headless browser sessions with
|
|
4
|
+
* isolated pages, console logs, and network activity per session.
|
|
5
|
+
*
|
|
6
|
+
* Auto-cleans up sessions after 5 minutes of inactivity.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.browserPool = exports.BrowserSessionPool = void 0;
|
|
10
|
+
const SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
11
|
+
class BrowserSessionPool {
|
|
12
|
+
sessions = new Map();
|
|
13
|
+
cleanupTimer = null;
|
|
14
|
+
/** Create or retrieve a session. If sessionId is empty, creates a new one. */
|
|
15
|
+
async getOrCreate(sessionId) {
|
|
16
|
+
if (sessionId && this.sessions.has(sessionId)) {
|
|
17
|
+
const session = this.sessions.get(sessionId);
|
|
18
|
+
session.lastActivity = Date.now();
|
|
19
|
+
const activePage = session.pages.find(p => p.id === session.activePageId);
|
|
20
|
+
if (activePage && !activePage.page.isClosed()) {
|
|
21
|
+
return { sessionId, page: activePage.page };
|
|
22
|
+
}
|
|
23
|
+
// Active page closed — create a new one
|
|
24
|
+
return this.newPage(sessionId);
|
|
25
|
+
}
|
|
26
|
+
// Create new session
|
|
27
|
+
const id = sessionId ?? `br_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
|
+
const { chromium } = require("playwright");
|
|
30
|
+
const browser = await chromium.launch({ headless: true });
|
|
31
|
+
const page = await browser.newPage();
|
|
32
|
+
const browserPage = {
|
|
33
|
+
id: `pg_${Date.now()}`,
|
|
34
|
+
page,
|
|
35
|
+
consoleEntries: [],
|
|
36
|
+
networkEntries: [],
|
|
37
|
+
netIdx: 0,
|
|
38
|
+
};
|
|
39
|
+
const session = {
|
|
40
|
+
browser,
|
|
41
|
+
pages: [browserPage],
|
|
42
|
+
activePageId: browserPage.id,
|
|
43
|
+
initUrl: "",
|
|
44
|
+
createdAt: Date.now(),
|
|
45
|
+
lastActivity: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
this.sessions.set(id, session);
|
|
48
|
+
this.startCleanup();
|
|
49
|
+
// Attach listeners
|
|
50
|
+
this.attachListeners(browserPage);
|
|
51
|
+
return { sessionId: id, page };
|
|
52
|
+
}
|
|
53
|
+
/** Navigate the active page of a session. */
|
|
54
|
+
async getPage(sessionId) {
|
|
55
|
+
const session = this.sessions.get(sessionId);
|
|
56
|
+
if (!session)
|
|
57
|
+
return null;
|
|
58
|
+
session.lastActivity = Date.now();
|
|
59
|
+
const active = session.pages.find(p => p.id === session.activePageId);
|
|
60
|
+
if (!active || active.page.isClosed())
|
|
61
|
+
return null;
|
|
62
|
+
return active.page;
|
|
63
|
+
}
|
|
64
|
+
/** Open a new tab in an existing session. */
|
|
65
|
+
async newPage(sessionId) {
|
|
66
|
+
const session = this.sessions.get(sessionId);
|
|
67
|
+
if (!session)
|
|
68
|
+
throw new Error(`Session ${sessionId} not found`);
|
|
69
|
+
session.lastActivity = Date.now();
|
|
70
|
+
const page = await session.browser.newPage();
|
|
71
|
+
const browserPage = {
|
|
72
|
+
id: `pg_${Date.now()}`,
|
|
73
|
+
page,
|
|
74
|
+
consoleEntries: [],
|
|
75
|
+
networkEntries: [],
|
|
76
|
+
netIdx: 0,
|
|
77
|
+
};
|
|
78
|
+
session.pages.push(browserPage);
|
|
79
|
+
session.activePageId = browserPage.id;
|
|
80
|
+
this.attachListeners(browserPage);
|
|
81
|
+
return { sessionId, page };
|
|
82
|
+
}
|
|
83
|
+
/** Switch active tab. */
|
|
84
|
+
switchPage(sessionId, pageId) {
|
|
85
|
+
const session = this.sessions.get(sessionId);
|
|
86
|
+
if (!session)
|
|
87
|
+
return false;
|
|
88
|
+
const exists = session.pages.find(p => p.id === pageId && !p.page.isClosed());
|
|
89
|
+
if (!exists)
|
|
90
|
+
return false;
|
|
91
|
+
session.activePageId = pageId;
|
|
92
|
+
session.lastActivity = Date.now();
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/** Close a tab (or the active one if pageId omitted). */
|
|
96
|
+
async closePage(sessionId, pageId) {
|
|
97
|
+
const session = this.sessions.get(sessionId);
|
|
98
|
+
if (!session)
|
|
99
|
+
return false;
|
|
100
|
+
session.lastActivity = Date.now();
|
|
101
|
+
const targetId = pageId ?? session.activePageId;
|
|
102
|
+
const idx = session.pages.findIndex(p => p.id === targetId);
|
|
103
|
+
if (idx === -1)
|
|
104
|
+
return false;
|
|
105
|
+
const bp = session.pages[idx];
|
|
106
|
+
await bp.page.close().catch(() => { });
|
|
107
|
+
session.pages.splice(idx, 1);
|
|
108
|
+
// If we closed the active page, switch to another
|
|
109
|
+
if (session.activePageId === targetId && session.pages.length > 0) {
|
|
110
|
+
session.activePageId = session.pages[0].id;
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
/** Destroy a session completely. */
|
|
115
|
+
async destroy(sessionId) {
|
|
116
|
+
const session = this.sessions.get(sessionId);
|
|
117
|
+
if (!session)
|
|
118
|
+
return;
|
|
119
|
+
for (const bp of session.pages) {
|
|
120
|
+
await bp.page.close().catch(() => { });
|
|
121
|
+
}
|
|
122
|
+
await session.browser.close().catch(() => { });
|
|
123
|
+
this.sessions.delete(sessionId);
|
|
124
|
+
}
|
|
125
|
+
/** Destroy all sessions. */
|
|
126
|
+
async destroyAll() {
|
|
127
|
+
let count = 0;
|
|
128
|
+
for (const [id, session] of this.sessions) {
|
|
129
|
+
for (const bp of session.pages) {
|
|
130
|
+
await bp.page.close().catch(() => { });
|
|
131
|
+
}
|
|
132
|
+
await session.browser.close().catch(() => { });
|
|
133
|
+
this.sessions.delete(id);
|
|
134
|
+
count++;
|
|
135
|
+
}
|
|
136
|
+
if (this.cleanupTimer) {
|
|
137
|
+
clearInterval(this.cleanupTimer);
|
|
138
|
+
this.cleanupTimer = null;
|
|
139
|
+
}
|
|
140
|
+
return count;
|
|
141
|
+
}
|
|
142
|
+
/** Set the initial navigation URL for a session. */
|
|
143
|
+
setInitUrl(sessionId, url) {
|
|
144
|
+
const session = this.sessions.get(sessionId);
|
|
145
|
+
if (session && !session.initUrl) {
|
|
146
|
+
session.initUrl = url;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** List all active sessions with metadata. */
|
|
150
|
+
list() {
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
const result = [];
|
|
153
|
+
for (const [id, session] of this.sessions) {
|
|
154
|
+
const active = session.pages.find(p => p.id === session.activePageId && !p.page.isClosed());
|
|
155
|
+
const idleMs = now - session.lastActivity;
|
|
156
|
+
result.push({
|
|
157
|
+
sessionId: id,
|
|
158
|
+
initUrl: session.initUrl || "(no navigation yet)",
|
|
159
|
+
currentUrl: active ? active.page.url() : "(closed)",
|
|
160
|
+
pageCount: session.pages.filter(p => !p.page.isClosed()).length,
|
|
161
|
+
activePageId: session.activePageId,
|
|
162
|
+
createdAt: session.createdAt,
|
|
163
|
+
lastActivity: session.lastActivity,
|
|
164
|
+
status: idleMs > 60_000 ? "idle" : "active",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
/** Get console logs for active page. */
|
|
170
|
+
getConsole(sessionId) {
|
|
171
|
+
return this.getActivePageData(sessionId)?.consoleEntries ?? [];
|
|
172
|
+
}
|
|
173
|
+
/** Get network entries for active page. */
|
|
174
|
+
getNetwork(sessionId) {
|
|
175
|
+
return this.getActivePageData(sessionId)?.networkEntries ?? [];
|
|
176
|
+
}
|
|
177
|
+
/** Clear console logs for active page. */
|
|
178
|
+
clearConsole(sessionId) {
|
|
179
|
+
const bp = this.getActivePageData(sessionId);
|
|
180
|
+
if (bp)
|
|
181
|
+
bp.consoleEntries = [];
|
|
182
|
+
}
|
|
183
|
+
/** Clear network entries for active page. */
|
|
184
|
+
clearNetwork(sessionId) {
|
|
185
|
+
const bp = this.getActivePageData(sessionId);
|
|
186
|
+
if (bp)
|
|
187
|
+
bp.networkEntries = [];
|
|
188
|
+
}
|
|
189
|
+
/** Cache a screenshot base64 string for the session. */
|
|
190
|
+
cacheScreenshot(sessionId, base64) {
|
|
191
|
+
const session = this.sessions.get(sessionId);
|
|
192
|
+
if (session)
|
|
193
|
+
session.cachedScreenshot = base64;
|
|
194
|
+
}
|
|
195
|
+
/** Get cached screenshot base64 string. */
|
|
196
|
+
getCachedScreenshot(sessionId) {
|
|
197
|
+
const session = this.sessions.get(sessionId);
|
|
198
|
+
return session.cachedScreenshot ?? null;
|
|
199
|
+
}
|
|
200
|
+
/** List all open tabs in a session. */
|
|
201
|
+
listPages(sessionId) {
|
|
202
|
+
const session = this.sessions.get(sessionId);
|
|
203
|
+
if (!session)
|
|
204
|
+
return [];
|
|
205
|
+
return session.pages
|
|
206
|
+
.filter(p => !p.page.isClosed())
|
|
207
|
+
.map(p => ({
|
|
208
|
+
id: p.id,
|
|
209
|
+
url: p.page.url(),
|
|
210
|
+
title: "", // Will be filled by caller if needed
|
|
211
|
+
active: p.id === session.activePageId,
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
// ── Private ────────────────────────────────────────────────────────────────
|
|
215
|
+
getActivePageData(sessionId) {
|
|
216
|
+
const session = this.sessions.get(sessionId);
|
|
217
|
+
if (!session)
|
|
218
|
+
return null;
|
|
219
|
+
session.lastActivity = Date.now();
|
|
220
|
+
return session.pages.find(p => p.id === session.activePageId && !p.page.isClosed()) ?? null;
|
|
221
|
+
}
|
|
222
|
+
attachListeners(bp) {
|
|
223
|
+
// Console
|
|
224
|
+
bp.page.on("console", (msg) => {
|
|
225
|
+
bp.consoleEntries.push({
|
|
226
|
+
type: msg.type(),
|
|
227
|
+
text: msg.text(),
|
|
228
|
+
location: msg.location().url ? `${msg.location().url}:${msg.location().lineNumber}` : "",
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
// Network
|
|
233
|
+
const timings = new Map();
|
|
234
|
+
bp.page.on("request", (req) => {
|
|
235
|
+
const idx = ++bp.netIdx;
|
|
236
|
+
timings.set(req.url() + req.method(), Date.now());
|
|
237
|
+
let reqBody;
|
|
238
|
+
try {
|
|
239
|
+
reqBody = req.postData() ?? undefined;
|
|
240
|
+
}
|
|
241
|
+
catch { }
|
|
242
|
+
bp.networkEntries.push({
|
|
243
|
+
idx, method: req.method(), url: req.url(),
|
|
244
|
+
reqHeaders: req.headers(),
|
|
245
|
+
reqBody, timestamp: Date.now(),
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
bp.page.on("response", async (resp) => {
|
|
249
|
+
const key = resp.url() + resp.request().method();
|
|
250
|
+
const start = timings.get(key);
|
|
251
|
+
const duration = start ? Date.now() - start : undefined;
|
|
252
|
+
let entry = bp.networkEntries.find(e => e.url === resp.url() && e.method === resp.request().method());
|
|
253
|
+
if (!entry) {
|
|
254
|
+
entry = { idx: ++bp.netIdx, method: resp.request().method(), url: resp.url(), timestamp: Date.now() };
|
|
255
|
+
bp.networkEntries.push(entry);
|
|
256
|
+
}
|
|
257
|
+
entry.status = resp.status();
|
|
258
|
+
entry.statusText = resp.statusText();
|
|
259
|
+
entry.duration = duration;
|
|
260
|
+
entry.resHeaders = resp.headers();
|
|
261
|
+
try {
|
|
262
|
+
const ct = resp.headers()["content-type"] ?? "";
|
|
263
|
+
if (ct.includes("json") || ct.includes("text") || ct.includes("xml") || ct.includes("javascript")) {
|
|
264
|
+
entry.resBody = await resp.text().catch(() => undefined);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch { }
|
|
268
|
+
});
|
|
269
|
+
bp.page.on("requestfailed", (req) => {
|
|
270
|
+
bp.networkEntries.push({
|
|
271
|
+
idx: ++bp.netIdx, method: req.method(), url: req.url(),
|
|
272
|
+
error: req.failure()?.errorText ?? "Unknown error",
|
|
273
|
+
reqHeaders: req.headers(),
|
|
274
|
+
timestamp: Date.now(),
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
startCleanup() {
|
|
279
|
+
if (this.cleanupTimer)
|
|
280
|
+
return;
|
|
281
|
+
this.cleanupTimer = setInterval(() => {
|
|
282
|
+
const now = Date.now();
|
|
283
|
+
for (const [id, session] of this.sessions) {
|
|
284
|
+
if (now - session.lastActivity > SESSION_TTL_MS) {
|
|
285
|
+
for (const bp of session.pages) {
|
|
286
|
+
bp.page.close().catch(() => { });
|
|
287
|
+
}
|
|
288
|
+
session.browser.close().catch(() => { });
|
|
289
|
+
this.sessions.delete(id);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (this.sessions.size === 0 && this.cleanupTimer) {
|
|
293
|
+
clearInterval(this.cleanupTimer);
|
|
294
|
+
this.cleanupTimer = null;
|
|
295
|
+
}
|
|
296
|
+
}, 60_000).unref();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
exports.BrowserSessionPool = BrowserSessionPool;
|
|
300
|
+
/** Singleton instance */
|
|
301
|
+
exports.browserPool = new BrowserSessionPool();
|
|
302
|
+
//# sourceMappingURL=browser-session-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-session-pool.js","sourceRoot":"","sources":["../../../src/tools/workspace/browser-session-pool.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAyCH,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,YAAY;AAEjD,MAAa,kBAAkB;IACrB,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAA;IAC5C,YAAY,GAA0C,IAAI,CAAA;IAElE,8EAA8E;IAC9E,KAAK,CAAC,WAAW,CAAC,SAAkB;QAClC,IAAI,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAE,CAAA;YAC7C,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACjC,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;YACzE,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC9C,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAA;YAC7C,CAAC;YACD,wCAAwC;YACxC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAChC,CAAC;QAED,qBAAqB;QACrB,MAAM,EAAE,GAAG,SAAS,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACpF,iEAAiE;QACjE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,YAAY,CAAgC,CAAA;QACzE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;QAEpC,MAAM,WAAW,GAAgB;YAC/B,EAAE,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE;YACtB,IAAI;YACJ,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,MAAM,EAAE,CAAC;SACV,CAAA;QAED,MAAM,OAAO,GAAmB;YAC9B,OAAO;YACP,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,YAAY,EAAE,WAAW,CAAC,EAAE;YAC5B,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;SACzB,CAAA;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QAC9B,IAAI,CAAC,YAAY,EAAE,CAAA;QAEnB,mBAAmB;QACnB,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;QAEjC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;IAChC,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,OAAO,CAAC,SAAiB;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;QACrE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO,IAAI,CAAA;QAClD,OAAO,MAAM,CAAC,IAAI,CAAA;IACpB,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,OAAO,CAAC,SAAiB;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,YAAY,CAAC,CAAA;QAE/D,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACjC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;QAE5C,MAAM,WAAW,GAAgB;YAC/B,EAAE,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE;YACtB,IAAI;YACJ,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,MAAM,EAAE,CAAC;SACV,CAAA;QAED,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAC/B,OAAO,CAAC,YAAY,GAAG,WAAW,CAAC,EAAE,CAAA;QACrC,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;QAEjC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;IAC5B,CAAC;IAED,yBAAyB;IACzB,UAAU,CAAC,SAAiB,EAAE,MAAc;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7E,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QACzB,OAAO,CAAC,YAAY,GAAG,MAAM,CAAA;QAC7B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACjC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,yDAAyD;IACzD,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,MAAe;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAC1B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAEjC,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAC,YAAY,CAAA;QAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAA;QAC3D,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QAE5B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAE,CAAA;QAC9B,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACrC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QAE5B,kDAAkD;QAClD,IAAI,OAAO,CAAC,YAAY,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClE,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAA;QAC7C,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAED,oCAAoC;IACpC,KAAK,CAAC,OAAO,CAAC,SAAiB;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAM;QAEpB,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACvC,CAAC;QACD,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;IAED,4BAA4B;IAC5B,KAAK,CAAC,UAAU;QACd,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1C,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC/B,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACvC,CAAC;YACD,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACxB,KAAK,EAAE,CAAA;QACT,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YAChC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QAC1B,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,oDAAoD;IACpD,UAAU,CAAC,SAAiB,EAAE,GAAW;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAA;QACvB,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI;QAUF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,MAAM,GASP,EAAE,CAAA;QAEP,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;YAC3F,MAAM,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,YAAY,CAAA;YACzC,MAAM,CAAC,IAAI,CAAC;gBACV,SAAS,EAAE,EAAE;gBACb,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,qBAAqB;gBACjD,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU;gBACnD,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM;gBAC/D,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;aAC5C,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,wCAAwC;IACxC,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,cAAc,IAAI,EAAE,CAAA;IAChE,CAAC;IAED,2CAA2C;IAC3C,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,cAAc,IAAI,EAAE,CAAA;IAChE,CAAC;IAED,0CAA0C;IAC1C,YAAY,CAAC,SAAiB;QAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,EAAE;YAAE,EAAE,CAAC,cAAc,GAAG,EAAE,CAAA;IAChC,CAAC;IAED,6CAA6C;IAC7C,YAAY,CAAC,SAAiB;QAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,EAAE;YAAE,EAAE,CAAC,cAAc,GAAG,EAAE,CAAA;IAChC,CAAC;IAED,wDAAwD;IACxD,eAAe,CAAC,SAAiB,EAAE,MAAc;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,OAAO;YAAG,OAAe,CAAC,gBAAgB,GAAG,MAAM,CAAA;IACzD,CAAC;IAED,2CAA2C;IAC3C,mBAAmB,CAAC,SAAiB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,OAAQ,OAAe,CAAC,gBAAgB,IAAI,IAAI,CAAA;IAClD,CAAC;IAED,uCAAuC;IACvC,SAAS,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAA;QACvB,OAAO,OAAO,CAAC,KAAK;aACjB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;aAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACT,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YACjB,KAAK,EAAE,EAAE,EAAE,qCAAqC;YAChD,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,YAAY;SACtC,CAAC,CAAC,CAAA;IACP,CAAC;IAED,8EAA8E;IAEtE,iBAAiB,CAAC,SAAiB;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACjC,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAA;IAC7F,CAAC;IAEO,eAAe,CAAC,EAAe;QACrC,UAAU;QACV,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;YAC5B,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC;gBACrB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;gBAChB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;gBAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;gBACxF,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,UAAU;QACV,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;QACzC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;YAC5B,MAAM,GAAG,GAAG,EAAE,EAAE,CAAC,MAAM,CAAA;YACvB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;YACjD,IAAI,OAA2B,CAAA;YAC/B,IAAI,CAAC;gBAAC,OAAO,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,SAAS,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACtD,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC;gBACrB,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE;gBACzC,UAAU,EAAE,GAAG,CAAC,OAAO,EAA4B;gBACnD,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aAC/B,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QACF,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAA;YAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;YACvD,IAAI,KAAK,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAA;YACrG,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,KAAK,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;gBACrG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC/B,CAAC;YACD,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;YAC5B,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAA;YACpC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;YACzB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,EAA4B,CAAA;YAC3D,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;gBAC/C,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;oBAClG,KAAK,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;gBAC1D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC,CAAC,CAAA;QACF,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE;YAClC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC;gBACrB,GAAG,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE;gBACtD,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,IAAI,eAAe;gBAClD,UAAU,EAAE,GAAG,CAAC,OAAO,EAA4B;gBACnD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,YAAY;YAAE,OAAM;QAC7B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1C,IAAI,GAAG,GAAG,OAAO,CAAC,YAAY,GAAG,cAAc,EAAE,CAAC;oBAChD,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;wBAC/B,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;oBACjC,CAAC;oBACD,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;oBACvC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBAC1B,CAAC;YACH,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClD,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;gBAChC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;YAC1B,CAAC;QACH,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;CACF;AApUD,gDAoUC;AAED,yBAAyB;AACZ,QAAA,WAAW,GAAG,IAAI,kBAAkB,EAAE,CAAA"}
|