openchrome-mcp 1.9.0 → 1.9.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.
- package/README.md +55 -1
- package/dist/cdp/client.d.ts +6 -0
- package/dist/cdp/client.d.ts.map +1 -1
- package/dist/cdp/client.js +13 -0
- package/dist/cdp/client.js.map +1 -1
- package/dist/chrome/headed-fallback.d.ts +3 -0
- package/dist/chrome/headed-fallback.d.ts.map +1 -1
- package/dist/chrome/headed-fallback.js +4 -0
- package/dist/chrome/headed-fallback.js.map +1 -1
- package/dist/cli/index.js +0 -0
- package/dist/config/global.d.ts +1 -0
- package/dist/config/global.d.ts.map +1 -1
- package/dist/config/global.js.map +1 -1
- package/dist/config/tool-tiers.d.ts.map +1 -1
- package/dist/config/tool-tiers.js +3 -0
- package/dist/config/tool-tiers.js.map +1 -1
- package/dist/connect/clipboard.d.ts +6 -0
- package/dist/connect/clipboard.d.ts.map +1 -0
- package/dist/connect/clipboard.js +54 -0
- package/dist/connect/clipboard.js.map +1 -0
- package/dist/connect/config-generator.d.ts +9 -0
- package/dist/connect/config-generator.d.ts.map +1 -0
- package/dist/connect/config-generator.js +43 -0
- package/dist/connect/config-generator.js.map +1 -0
- package/dist/connect/hosts.d.ts +9 -0
- package/dist/connect/hosts.d.ts.map +1 -0
- package/dist/connect/hosts.js +81 -0
- package/dist/connect/hosts.js.map +1 -0
- package/dist/connect/index.d.ts +8 -0
- package/dist/connect/index.d.ts.map +1 -0
- package/dist/connect/index.js +15 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/connect/open-url.d.ts +6 -0
- package/dist/connect/open-url.d.ts.map +1 -0
- package/dist/connect/open-url.js +42 -0
- package/dist/connect/open-url.js.map +1 -0
- package/dist/connect/types.d.ts +48 -0
- package/dist/connect/types.d.ts.map +1 -0
- package/dist/connect/types.js +7 -0
- package/dist/connect/types.js.map +1 -0
- package/dist/dashboard/index.d.ts +3 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +47 -0
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/types.d.ts +1 -1
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/dashboard/views/connect-view.d.ts +25 -0
- package/dist/dashboard/views/connect-view.d.ts.map +1 -0
- package/dist/dashboard/views/connect-view.js +135 -0
- package/dist/dashboard/views/connect-view.js.map +1 -0
- package/dist/dashboard/views/main-view.d.ts.map +1 -1
- package/dist/dashboard/views/main-view.js +1 -0
- package/dist/dashboard/views/main-view.js.map +1 -1
- package/dist/desktop/chrome-detector.d.ts +58 -0
- package/dist/desktop/chrome-detector.d.ts.map +1 -0
- package/dist/desktop/chrome-detector.js +211 -0
- package/dist/desktop/chrome-detector.js.map +1 -0
- package/dist/desktop/cli-coexistence.d.ts +90 -0
- package/dist/desktop/cli-coexistence.d.ts.map +1 -0
- package/dist/desktop/cli-coexistence.js +219 -0
- package/dist/desktop/cli-coexistence.js.map +1 -0
- package/dist/desktop/dashboard-state.d.ts +50 -0
- package/dist/desktop/dashboard-state.d.ts.map +1 -0
- package/dist/desktop/dashboard-state.js +155 -0
- package/dist/desktop/dashboard-state.js.map +1 -0
- package/dist/desktop/error-log.d.ts +53 -0
- package/dist/desktop/error-log.d.ts.map +1 -0
- package/dist/desktop/error-log.js +127 -0
- package/dist/desktop/error-log.js.map +1 -0
- package/dist/desktop/sidecar-manager.d.ts +80 -0
- package/dist/desktop/sidecar-manager.d.ts.map +1 -0
- package/dist/desktop/sidecar-manager.js +222 -0
- package/dist/desktop/sidecar-manager.js.map +1 -0
- package/dist/desktop/tunnel-failure-handler.d.ts +56 -0
- package/dist/desktop/tunnel-failure-handler.d.ts.map +1 -0
- package/dist/desktop/tunnel-failure-handler.js +157 -0
- package/dist/desktop/tunnel-failure-handler.js.map +1 -0
- package/dist/desktop/tunnel-manager.d.ts +85 -0
- package/dist/desktop/tunnel-manager.d.ts.map +1 -0
- package/dist/desktop/tunnel-manager.js +363 -0
- package/dist/desktop/tunnel-manager.js.map +1 -0
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +4 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/session-manager.d.ts +6 -0
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +12 -0
- package/dist/session-manager.js.map +1 -1
- package/dist/tools/connect.d.ts +7 -0
- package/dist/tools/connect.d.ts.map +1 -0
- package/dist/tools/connect.js +125 -0
- package/dist/tools/connect.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/navigate.d.ts.map +1 -1
- package/dist/tools/navigate.js +15 -6
- package/dist/tools/navigate.js.map +1 -1
- package/dist/transports/http.d.ts +26 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +161 -4
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/index.d.ts +1 -0
- package/dist/transports/index.d.ts.map +1 -1
- package/dist/transports/index.js +1 -1
- package/dist/transports/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/click-element.d.ts +0 -8
- package/dist/tools/click-element.d.ts.map +0 -1
- package/dist/tools/click-element.js +0 -347
- package/dist/tools/click-element.js.map +0 -1
- package/dist/tools/wait-and-click.d.ts +0 -8
- package/dist/tools/wait-and-click.d.ts.map +0 -1
- package/dist/tools/wait-and-click.js +0 -208
- package/dist/tools/wait-and-click.js.map +0 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLI Coexistence — detects and monitors an existing CLI-spawned server.
|
|
4
|
+
* On app start, checks if a server is already running on the target port.
|
|
5
|
+
* If found, connects to it instead of spawning a new sidecar.
|
|
6
|
+
* Monitors health continuously and emits events on state changes.
|
|
7
|
+
* Part of #524 Desktop App: Error handling + local fallback + CLI coexistence.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.CLICoexistence = void 0;
|
|
44
|
+
const events_1 = require("events");
|
|
45
|
+
const http = __importStar(require("http"));
|
|
46
|
+
/**
|
|
47
|
+
* Events emitted by CLICoexistence:
|
|
48
|
+
*
|
|
49
|
+
* 'external-detected' → { port: number }
|
|
50
|
+
* A server was found running on the configured port.
|
|
51
|
+
*
|
|
52
|
+
* 'external-lost' → { port: number; message: string }
|
|
53
|
+
* A previously-detected external server stopped responding.
|
|
54
|
+
*
|
|
55
|
+
* 'no-server' → { port: number }
|
|
56
|
+
* Initial check found no server running.
|
|
57
|
+
*
|
|
58
|
+
* 'health-check' → { healthy: boolean; source: ServerSource }
|
|
59
|
+
* Fired after every health check (initial and periodic).
|
|
60
|
+
*
|
|
61
|
+
* 'status-changed' → { oldSource: ServerSource; newSource: ServerSource }
|
|
62
|
+
* Fired when source transitions (none→external or external→none).
|
|
63
|
+
*/
|
|
64
|
+
class CLICoexistence extends events_1.EventEmitter {
|
|
65
|
+
port;
|
|
66
|
+
healthCheckPath;
|
|
67
|
+
healthCheckIntervalMs;
|
|
68
|
+
healthCheckTimeoutMs;
|
|
69
|
+
source = 'none';
|
|
70
|
+
healthy = false;
|
|
71
|
+
lastHealthCheck = null;
|
|
72
|
+
timer = null;
|
|
73
|
+
constructor(opts = {}) {
|
|
74
|
+
super();
|
|
75
|
+
this.port = opts.port ?? 3100;
|
|
76
|
+
this.healthCheckPath = opts.healthCheckPath ?? '/health';
|
|
77
|
+
this.healthCheckIntervalMs = opts.healthCheckIntervalMs ?? 5000;
|
|
78
|
+
this.healthCheckTimeoutMs = opts.healthCheckTimeoutMs ?? 2000;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Perform a single health check against the configured port.
|
|
82
|
+
* Returns a ServerInfo snapshot reflecting the result.
|
|
83
|
+
*/
|
|
84
|
+
async checkForExistingServer() {
|
|
85
|
+
const healthy = await this._httpGet();
|
|
86
|
+
this.lastHealthCheck = Date.now();
|
|
87
|
+
const oldSource = this.source;
|
|
88
|
+
if (healthy) {
|
|
89
|
+
if (this.source !== 'external' && this.source !== 'built-in') {
|
|
90
|
+
this.source = 'external';
|
|
91
|
+
}
|
|
92
|
+
this.healthy = true;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.healthy = false;
|
|
96
|
+
if (this.source === 'none') {
|
|
97
|
+
// Still none — no transition
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (oldSource !== this.source) {
|
|
101
|
+
this.emit('status-changed', { oldSource, newSource: this.source });
|
|
102
|
+
}
|
|
103
|
+
const info = this.getServerInfo();
|
|
104
|
+
this.emit('health-check', { healthy, source: this.source });
|
|
105
|
+
if (healthy && oldSource === 'none') {
|
|
106
|
+
this.emit('external-detected', { port: this.port });
|
|
107
|
+
}
|
|
108
|
+
else if (!healthy && oldSource === 'none') {
|
|
109
|
+
this.emit('no-server', { port: this.port });
|
|
110
|
+
}
|
|
111
|
+
return info;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Start periodic health monitoring.
|
|
115
|
+
* Timer is .unref()'d so it does not prevent process exit.
|
|
116
|
+
*/
|
|
117
|
+
startMonitoring() {
|
|
118
|
+
this.stopMonitoring(); // clear any existing timer
|
|
119
|
+
this.timer = setInterval(() => {
|
|
120
|
+
this._monitorTick().catch((err) => {
|
|
121
|
+
console.error('[CLICoexistence] Unexpected error in monitor tick:', err);
|
|
122
|
+
});
|
|
123
|
+
}, this.healthCheckIntervalMs);
|
|
124
|
+
this.timer.unref();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Stop periodic health monitoring.
|
|
128
|
+
*/
|
|
129
|
+
stopMonitoring() {
|
|
130
|
+
if (this.timer) {
|
|
131
|
+
clearInterval(this.timer);
|
|
132
|
+
this.timer = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Returns a snapshot of the current server info.
|
|
137
|
+
*/
|
|
138
|
+
getServerInfo() {
|
|
139
|
+
return {
|
|
140
|
+
source: this.source,
|
|
141
|
+
port: this.port,
|
|
142
|
+
healthy: this.healthy,
|
|
143
|
+
lastHealthCheck: this.lastHealthCheck,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Whether the monitoring timer is active.
|
|
148
|
+
*/
|
|
149
|
+
isMonitoring() {
|
|
150
|
+
return this.timer !== null;
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Internal helpers
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
async _monitorTick() {
|
|
156
|
+
const prevSource = this.source;
|
|
157
|
+
const healthy = await this._httpGet();
|
|
158
|
+
this.lastHealthCheck = Date.now();
|
|
159
|
+
this.healthy = healthy;
|
|
160
|
+
this.emit('health-check', { healthy, source: this.source });
|
|
161
|
+
if (prevSource === 'external' && !healthy) {
|
|
162
|
+
// External server just stopped
|
|
163
|
+
this.source = 'none';
|
|
164
|
+
this.emit('status-changed', { oldSource: prevSource, newSource: this.source });
|
|
165
|
+
this.emit('external-lost', {
|
|
166
|
+
port: this.port,
|
|
167
|
+
message: 'External server stopped. Start built-in server?',
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
else if (prevSource === 'none' && healthy) {
|
|
171
|
+
// Server appeared while monitoring (e.g., CLI was started externally)
|
|
172
|
+
this.source = 'external';
|
|
173
|
+
this.emit('status-changed', { oldSource: prevSource, newSource: this.source });
|
|
174
|
+
this.emit('external-detected', { port: this.port });
|
|
175
|
+
}
|
|
176
|
+
else if (prevSource === 'built-in' && !healthy) {
|
|
177
|
+
// Built-in server lost health — just update healthy flag, no source change
|
|
178
|
+
this.healthy = false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Attempt GET {healthCheckPath} on localhost:{port}.
|
|
183
|
+
* Returns true if a 2xx/3xx response is received within the timeout.
|
|
184
|
+
* Returns false on ECONNREFUSED, ETIMEDOUT, or any error.
|
|
185
|
+
*/
|
|
186
|
+
_httpGet() {
|
|
187
|
+
return new Promise((resolve) => {
|
|
188
|
+
const options = {
|
|
189
|
+
hostname: '127.0.0.1',
|
|
190
|
+
port: this.port,
|
|
191
|
+
path: this.healthCheckPath,
|
|
192
|
+
method: 'GET',
|
|
193
|
+
timeout: this.healthCheckTimeoutMs,
|
|
194
|
+
};
|
|
195
|
+
const req = http.get(options, (res) => {
|
|
196
|
+
// Drain the response body to free the socket
|
|
197
|
+
res.resume();
|
|
198
|
+
// Any HTTP response (even 503) means the server is reachable
|
|
199
|
+
resolve(true);
|
|
200
|
+
});
|
|
201
|
+
req.on('timeout', () => {
|
|
202
|
+
req.destroy();
|
|
203
|
+
resolve(false);
|
|
204
|
+
});
|
|
205
|
+
req.on('error', (err) => {
|
|
206
|
+
if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT' || err.code === 'ECONNRESET') {
|
|
207
|
+
resolve(false);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// Any other network error — treat as unavailable
|
|
211
|
+
console.error('[CLICoexistence] Health check error:', err.code, err.message);
|
|
212
|
+
resolve(false);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.CLICoexistence = CLICoexistence;
|
|
219
|
+
//# sourceMappingURL=cli-coexistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-coexistence.js","sourceRoot":"","sources":["../../src/desktop/cli-coexistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard State - Tracks tool calls and session info for the desktop dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Provides a lightweight ring buffer of recent tool calls per session,
|
|
5
|
+
* consumed by the REST API endpoints in the HTTP transport.
|
|
6
|
+
*/
|
|
7
|
+
export interface DashboardToolCall {
|
|
8
|
+
id: string;
|
|
9
|
+
toolName: string;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
args: string;
|
|
12
|
+
status: 'running' | 'success' | 'error';
|
|
13
|
+
startTime: number;
|
|
14
|
+
endTime?: number;
|
|
15
|
+
duration?: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SessionSummary {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
totalCalls: number;
|
|
21
|
+
activeCalls: number;
|
|
22
|
+
lastActivity: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class DashboardState {
|
|
25
|
+
private calls;
|
|
26
|
+
private activeCalls;
|
|
27
|
+
private startTime;
|
|
28
|
+
/**
|
|
29
|
+
* Record the start of a tool call. Returns the call ID for later completion.
|
|
30
|
+
*/
|
|
31
|
+
recordToolStart(sessionId: string, toolName: string, args: Record<string, unknown> | undefined, callId: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Record the end of a tool call.
|
|
34
|
+
*/
|
|
35
|
+
recordToolEnd(callId: string, status: 'success' | 'error', error?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Get tool calls, optionally filtered by session and limited.
|
|
38
|
+
*/
|
|
39
|
+
getToolCalls(sessionId?: string, limit?: number): DashboardToolCall[];
|
|
40
|
+
/**
|
|
41
|
+
* Get summaries for all sessions that have had tool calls.
|
|
42
|
+
*/
|
|
43
|
+
getSessionSummaries(): SessionSummary[];
|
|
44
|
+
/**
|
|
45
|
+
* Get server uptime in seconds.
|
|
46
|
+
*/
|
|
47
|
+
getUptimeSecs(): number;
|
|
48
|
+
}
|
|
49
|
+
export declare function getDashboardState(): DashboardState;
|
|
50
|
+
//# sourceMappingURL=dashboard-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-state.d.ts","sourceRoot":"","sources":["../../src/desktop/dashboard-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AA6DD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAmD;IAChE,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,SAAS,CAAc;IAE/B;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAcrH;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAahF;;OAEG;IACH,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAOrE;;OAEG;IACH,mBAAmB,IAAI,cAAc,EAAE;IAYvC;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB;AAkBD,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dashboard State - Tracks tool calls and session info for the desktop dashboard.
|
|
4
|
+
*
|
|
5
|
+
* Provides a lightweight ring buffer of recent tool calls per session,
|
|
6
|
+
* consumed by the REST API endpoints in the HTTP transport.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DashboardState = void 0;
|
|
10
|
+
exports.getDashboardState = getDashboardState;
|
|
11
|
+
/** Maximum tool calls retained per session */
|
|
12
|
+
const MAX_CALLS_PER_SESSION = 50;
|
|
13
|
+
/**
|
|
14
|
+
* Ring buffer that retains at most `capacity` items per session.
|
|
15
|
+
*/
|
|
16
|
+
class PerSessionRingBuffer {
|
|
17
|
+
buffers = new Map();
|
|
18
|
+
capacity;
|
|
19
|
+
constructor(capacity) {
|
|
20
|
+
this.capacity = capacity;
|
|
21
|
+
}
|
|
22
|
+
push(sessionId, call) {
|
|
23
|
+
let buf = this.buffers.get(sessionId);
|
|
24
|
+
if (!buf) {
|
|
25
|
+
buf = [];
|
|
26
|
+
this.buffers.set(sessionId, buf);
|
|
27
|
+
}
|
|
28
|
+
buf.unshift(call);
|
|
29
|
+
if (buf.length > this.capacity) {
|
|
30
|
+
buf.length = this.capacity;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
get(sessionId, limit) {
|
|
34
|
+
const buf = this.buffers.get(sessionId);
|
|
35
|
+
if (!buf)
|
|
36
|
+
return [];
|
|
37
|
+
return limit ? buf.slice(0, limit) : buf.slice();
|
|
38
|
+
}
|
|
39
|
+
getAll(limit) {
|
|
40
|
+
const all = [];
|
|
41
|
+
for (const buf of this.buffers.values()) {
|
|
42
|
+
all.push(...buf);
|
|
43
|
+
}
|
|
44
|
+
// Sort by startTime descending (most recent first)
|
|
45
|
+
all.sort((a, b) => b.startTime - a.startTime);
|
|
46
|
+
return limit ? all.slice(0, limit) : all;
|
|
47
|
+
}
|
|
48
|
+
sessionIds() {
|
|
49
|
+
return Array.from(this.buffers.keys());
|
|
50
|
+
}
|
|
51
|
+
sessionStats(sessionId) {
|
|
52
|
+
const buf = this.buffers.get(sessionId);
|
|
53
|
+
if (!buf || buf.length === 0) {
|
|
54
|
+
return { total: 0, active: 0, lastActivity: 0 };
|
|
55
|
+
}
|
|
56
|
+
let active = 0;
|
|
57
|
+
let lastActivity = 0;
|
|
58
|
+
for (const call of buf) {
|
|
59
|
+
if (call.status === 'running')
|
|
60
|
+
active++;
|
|
61
|
+
const t = call.endTime || call.startTime;
|
|
62
|
+
if (t > lastActivity)
|
|
63
|
+
lastActivity = t;
|
|
64
|
+
}
|
|
65
|
+
return { total: buf.length, active, lastActivity };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class DashboardState {
|
|
69
|
+
calls = new PerSessionRingBuffer(MAX_CALLS_PER_SESSION);
|
|
70
|
+
activeCalls = new Map();
|
|
71
|
+
startTime = Date.now();
|
|
72
|
+
/**
|
|
73
|
+
* Record the start of a tool call. Returns the call ID for later completion.
|
|
74
|
+
*/
|
|
75
|
+
recordToolStart(sessionId, toolName, args, callId) {
|
|
76
|
+
const argSummary = args ? summarizeArgs(args) : '';
|
|
77
|
+
const call = {
|
|
78
|
+
id: callId,
|
|
79
|
+
toolName,
|
|
80
|
+
sessionId,
|
|
81
|
+
args: argSummary,
|
|
82
|
+
status: 'running',
|
|
83
|
+
startTime: Date.now(),
|
|
84
|
+
};
|
|
85
|
+
this.activeCalls.set(callId, call);
|
|
86
|
+
this.calls.push(sessionId, call);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Record the end of a tool call.
|
|
90
|
+
*/
|
|
91
|
+
recordToolEnd(callId, status, error) {
|
|
92
|
+
const call = this.activeCalls.get(callId);
|
|
93
|
+
if (!call)
|
|
94
|
+
return;
|
|
95
|
+
call.status = status;
|
|
96
|
+
call.endTime = Date.now();
|
|
97
|
+
call.duration = call.endTime - call.startTime;
|
|
98
|
+
if (error) {
|
|
99
|
+
call.error = error;
|
|
100
|
+
}
|
|
101
|
+
this.activeCalls.delete(callId);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get tool calls, optionally filtered by session and limited.
|
|
105
|
+
*/
|
|
106
|
+
getToolCalls(sessionId, limit) {
|
|
107
|
+
if (sessionId) {
|
|
108
|
+
return this.calls.get(sessionId, limit);
|
|
109
|
+
}
|
|
110
|
+
return this.calls.getAll(limit);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get summaries for all sessions that have had tool calls.
|
|
114
|
+
*/
|
|
115
|
+
getSessionSummaries() {
|
|
116
|
+
return this.calls.sessionIds().map((sid) => {
|
|
117
|
+
const stats = this.calls.sessionStats(sid);
|
|
118
|
+
return {
|
|
119
|
+
sessionId: sid,
|
|
120
|
+
totalCalls: stats.total,
|
|
121
|
+
activeCalls: stats.active,
|
|
122
|
+
lastActivity: stats.lastActivity,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get server uptime in seconds.
|
|
128
|
+
*/
|
|
129
|
+
getUptimeSecs() {
|
|
130
|
+
return Math.floor((Date.now() - this.startTime) / 1000);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.DashboardState = DashboardState;
|
|
134
|
+
/**
|
|
135
|
+
* Summarize tool args into a short string for dashboard display.
|
|
136
|
+
* Truncates to 200 chars to avoid bloating the ring buffer.
|
|
137
|
+
*/
|
|
138
|
+
function summarizeArgs(args) {
|
|
139
|
+
try {
|
|
140
|
+
const str = JSON.stringify(args);
|
|
141
|
+
return str.length > 200 ? str.slice(0, 197) + '...' : str;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return '[unserializable]';
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Singleton
|
|
148
|
+
let instance = null;
|
|
149
|
+
function getDashboardState() {
|
|
150
|
+
if (!instance) {
|
|
151
|
+
instance = new DashboardState();
|
|
152
|
+
}
|
|
153
|
+
return instance;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=dashboard-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-state.js","sourceRoot":"","sources":["../../src/desktop/dashboard-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Log Ring Buffer — in-memory log storage for the desktop app sidecar.
|
|
3
|
+
*
|
|
4
|
+
* Stores the last N log entries (default 100) and strips sensitive data before
|
|
5
|
+
* storage so logs can safely be copied to clipboard for bug reports.
|
|
6
|
+
*
|
|
7
|
+
* Sensitive patterns redacted:
|
|
8
|
+
* - Bearer tokens
|
|
9
|
+
* - JWT strings
|
|
10
|
+
* - Cookie values
|
|
11
|
+
* - Authorization headers
|
|
12
|
+
*/
|
|
13
|
+
export interface LogEntry {
|
|
14
|
+
timestamp: number;
|
|
15
|
+
level: 'info' | 'warn' | 'error';
|
|
16
|
+
source: string;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class ErrorLogBuffer {
|
|
20
|
+
private readonly maxEntries;
|
|
21
|
+
private buffer;
|
|
22
|
+
private head;
|
|
23
|
+
private count;
|
|
24
|
+
constructor(maxEntries?: number);
|
|
25
|
+
/**
|
|
26
|
+
* Append a new log entry. When the buffer is full the oldest entry is
|
|
27
|
+
* overwritten (ring buffer behaviour).
|
|
28
|
+
*/
|
|
29
|
+
append(level: LogEntry['level'], source: string, message: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Return all entries in chronological order (oldest first).
|
|
32
|
+
*/
|
|
33
|
+
getAll(): LogEntry[];
|
|
34
|
+
/**
|
|
35
|
+
* Return the last `count` entries in chronological order (oldest first).
|
|
36
|
+
* Defaults to all entries when count is omitted.
|
|
37
|
+
*/
|
|
38
|
+
getLatest(count?: number): LogEntry[];
|
|
39
|
+
/**
|
|
40
|
+
* Remove all entries from the buffer.
|
|
41
|
+
*/
|
|
42
|
+
clear(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Format the buffer contents as a multi-line string suitable for
|
|
45
|
+
* copying to the clipboard when filing a bug report.
|
|
46
|
+
*/
|
|
47
|
+
toClipboardText(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Return the number of entries currently stored in the buffer.
|
|
50
|
+
*/
|
|
51
|
+
getSize(): number;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=error-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-log.d.ts","sourceRoot":"","sources":["../../src/desktop/error-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAmBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAAS;gBAEV,UAAU,GAAE,MAAY;IAapC;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgBvE;;OAEG;IACH,MAAM,IAAI,QAAQ,EAAE;IAgBpB;;;OAGG;IACH,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE;IAWrC;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;;OAGG;IACH,eAAe,IAAI,MAAM;IAczB;;OAEG;IACH,OAAO,IAAI,MAAM;CAGlB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error Log Ring Buffer — in-memory log storage for the desktop app sidecar.
|
|
4
|
+
*
|
|
5
|
+
* Stores the last N log entries (default 100) and strips sensitive data before
|
|
6
|
+
* storage so logs can safely be copied to clipboard for bug reports.
|
|
7
|
+
*
|
|
8
|
+
* Sensitive patterns redacted:
|
|
9
|
+
* - Bearer tokens
|
|
10
|
+
* - JWT strings
|
|
11
|
+
* - Cookie values
|
|
12
|
+
* - Authorization headers
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.ErrorLogBuffer = void 0;
|
|
16
|
+
// Patterns that must be redacted before storing a log message.
|
|
17
|
+
const BEARER_TOKEN = /Bearer\s+[A-Za-z0-9._-]+/g;
|
|
18
|
+
const JWT_PATTERN = /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
19
|
+
const COOKIE_VALUE = /(\bcookie\b[^=\n]*=\s*)([^;\n]+)/gi;
|
|
20
|
+
const AUTH_HEADER = /(Authorization:\s*).*/gi;
|
|
21
|
+
/**
|
|
22
|
+
* Strip sensitive information from a log message before it enters the buffer.
|
|
23
|
+
*/
|
|
24
|
+
function redact(message) {
|
|
25
|
+
return message
|
|
26
|
+
.replace(JWT_PATTERN, '[REDACTED_JWT]')
|
|
27
|
+
.replace(BEARER_TOKEN, 'Bearer [REDACTED]')
|
|
28
|
+
.replace(COOKIE_VALUE, '$1[REDACTED]')
|
|
29
|
+
.replace(AUTH_HEADER, '$1[REDACTED]');
|
|
30
|
+
}
|
|
31
|
+
class ErrorLogBuffer {
|
|
32
|
+
maxEntries;
|
|
33
|
+
buffer;
|
|
34
|
+
head; // index of the oldest entry (write position)
|
|
35
|
+
count; // number of valid entries currently in the buffer
|
|
36
|
+
constructor(maxEntries = 100) {
|
|
37
|
+
if (maxEntries < 1) {
|
|
38
|
+
throw new RangeError('maxEntries must be at least 1');
|
|
39
|
+
}
|
|
40
|
+
if (maxEntries > 10_000) {
|
|
41
|
+
throw new RangeError('maxEntries must be at most 10000');
|
|
42
|
+
}
|
|
43
|
+
this.maxEntries = maxEntries;
|
|
44
|
+
this.buffer = new Array(maxEntries);
|
|
45
|
+
this.head = 0;
|
|
46
|
+
this.count = 0;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Append a new log entry. When the buffer is full the oldest entry is
|
|
50
|
+
* overwritten (ring buffer behaviour).
|
|
51
|
+
*/
|
|
52
|
+
append(level, source, message) {
|
|
53
|
+
const entry = {
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
level,
|
|
56
|
+
source,
|
|
57
|
+
message: redact(message),
|
|
58
|
+
};
|
|
59
|
+
this.buffer[this.head] = entry;
|
|
60
|
+
this.head = (this.head + 1) % this.maxEntries;
|
|
61
|
+
if (this.count < this.maxEntries) {
|
|
62
|
+
this.count++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Return all entries in chronological order (oldest first).
|
|
67
|
+
*/
|
|
68
|
+
getAll() {
|
|
69
|
+
if (this.count === 0) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
if (this.count < this.maxEntries) {
|
|
73
|
+
// Buffer is not yet full; entries start at index 0.
|
|
74
|
+
return this.buffer.slice(0, this.count);
|
|
75
|
+
}
|
|
76
|
+
// Buffer is full; oldest entry is at this.head.
|
|
77
|
+
const tail = this.buffer.slice(this.head);
|
|
78
|
+
const wrappedHead = this.buffer.slice(0, this.head);
|
|
79
|
+
return [...tail, ...wrappedHead];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Return the last `count` entries in chronological order (oldest first).
|
|
83
|
+
* Defaults to all entries when count is omitted.
|
|
84
|
+
*/
|
|
85
|
+
getLatest(count) {
|
|
86
|
+
const all = this.getAll();
|
|
87
|
+
if (count === undefined || !Number.isFinite(count) || count >= all.length) {
|
|
88
|
+
return all;
|
|
89
|
+
}
|
|
90
|
+
if (count <= 0) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
return all.slice(all.length - count);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Remove all entries from the buffer.
|
|
97
|
+
*/
|
|
98
|
+
clear() {
|
|
99
|
+
this.buffer = new Array(this.maxEntries);
|
|
100
|
+
this.head = 0;
|
|
101
|
+
this.count = 0;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format the buffer contents as a multi-line string suitable for
|
|
105
|
+
* copying to the clipboard when filing a bug report.
|
|
106
|
+
*/
|
|
107
|
+
toClipboardText() {
|
|
108
|
+
const entries = this.getAll();
|
|
109
|
+
if (entries.length === 0) {
|
|
110
|
+
return '(no log entries)';
|
|
111
|
+
}
|
|
112
|
+
return entries
|
|
113
|
+
.map((e) => {
|
|
114
|
+
const ts = new Date(e.timestamp).toISOString();
|
|
115
|
+
return `[${ts}] [${e.level.toUpperCase()}] [${e.source}] ${e.message}`;
|
|
116
|
+
})
|
|
117
|
+
.join('\n');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Return the number of entries currently stored in the buffer.
|
|
121
|
+
*/
|
|
122
|
+
getSize() {
|
|
123
|
+
return this.count;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.ErrorLogBuffer = ErrorLogBuffer;
|
|
127
|
+
//# sourceMappingURL=error-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-log.js","sourceRoot":"","sources":["../../src/desktop/error-log.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AASH,+DAA+D;AAC/D,MAAM,YAAY,GAAG,2BAA2B,CAAC;AACjD,MAAM,WAAW,GAAG,uDAAuD,CAAC;AAC5E,MAAM,YAAY,GAAG,oCAAoC,CAAC;AAC1D,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAE9C;;GAEG;AACH,SAAS,MAAM,CAAC,OAAe;IAC7B,OAAO,OAAO;SACX,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC;SACtC,OAAO,CAAC,YAAY,EAAE,mBAAmB,CAAC;SAC1C,OAAO,CAAC,YAAY,EAAE,cAAc,CAAC;SACrC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAC1C,CAAC;AAED,MAAa,cAAc;IACR,UAAU,CAAS;IAC5B,MAAM,CAAa;IACnB,IAAI,CAAS,CAAC,6CAA6C;IAC3D,KAAK,CAAS,CAAC,kDAAkD;IAEzE,YAAY,aAAqB,GAAG;QAClC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,UAAU,GAAG,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,UAAU,CAAC,kCAAkC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAW,UAAU,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAwB,EAAE,MAAc,EAAE,OAAe;QAC9D,MAAM,KAAK,GAAa;YACtB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK;YACL,MAAM;YACN,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;SACzB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;QAE9C,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,oDAAoD;YACpD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED,gDAAgD;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,WAAW,CAAC,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,KAAc;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAC1E,OAAO,GAAG,CAAC;QACb,CAAC;QACD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAW,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,kBAAkB,CAAC;QAC5B,CAAC;QAED,OAAO,OAAO;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAC/C,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QACzE,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AA1GD,wCA0GC"}
|