@mclawnet/mcp-server 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Cross-process "wake the agent" shim.
3
+ *
4
+ * The MCP server lives in a stdio subprocess spawned by the LLM backend
5
+ * (claude / codex CLI); the agent process owns the real InboxRelay and runs an
6
+ * InboxWatcher (fs.watch on the inbox dir, 50ms debounce) that calls
7
+ * InboxRelay.deliver() whenever anything in the inbox dir changes.
8
+ *
9
+ * When this process needs to wake the agent — e.g. a `wakeup_after` timer
10
+ * fires, or a `watch_path` trigger just wrote a new inbox message — we can't
11
+ * call InboxRelay directly (different process). Instead we touch the
12
+ * recipient's inbox file's mtime so the agent's InboxWatcher picks it up and
13
+ * runs its normal deliver pass.
14
+ *
15
+ * `home` matches the value passed to InboxStore (CLAWNET_HOME or os.homedir());
16
+ * filenames live at `<projectRoot>/swarms/<swarmId>/inboxes/<instanceId>.json`.
17
+ */
18
+ export declare class InboxTouchRelay {
19
+ private home;
20
+ constructor(home: string);
21
+ deliver(workDir: string, swarmId: string, instanceId: string): void;
22
+ }
23
+ //# sourceMappingURL=inbox-touch-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-touch-relay.d.ts","sourceRoot":"","sources":["../src/inbox-touch-relay.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAEhC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAiBpE"}
@@ -0,0 +1,41 @@
1
+ import { utimesSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { projectRoot } from "@mclawnet/task";
4
+ import { createLogger } from "@mclawnet/logger";
5
+ const log = createLogger({ module: "mcp-server/inbox-touch-relay" });
6
+ /**
7
+ * Cross-process "wake the agent" shim.
8
+ *
9
+ * The MCP server lives in a stdio subprocess spawned by the LLM backend
10
+ * (claude / codex CLI); the agent process owns the real InboxRelay and runs an
11
+ * InboxWatcher (fs.watch on the inbox dir, 50ms debounce) that calls
12
+ * InboxRelay.deliver() whenever anything in the inbox dir changes.
13
+ *
14
+ * When this process needs to wake the agent — e.g. a `wakeup_after` timer
15
+ * fires, or a `watch_path` trigger just wrote a new inbox message — we can't
16
+ * call InboxRelay directly (different process). Instead we touch the
17
+ * recipient's inbox file's mtime so the agent's InboxWatcher picks it up and
18
+ * runs its normal deliver pass.
19
+ *
20
+ * `home` matches the value passed to InboxStore (CLAWNET_HOME or os.homedir());
21
+ * filenames live at `<projectRoot>/swarms/<swarmId>/inboxes/<instanceId>.json`.
22
+ */
23
+ export class InboxTouchRelay {
24
+ home;
25
+ constructor(home) {
26
+ this.home = home;
27
+ }
28
+ deliver(workDir, swarmId, instanceId) {
29
+ try {
30
+ const fp = join(projectRoot(workDir, this.home), "swarms", swarmId, "inboxes", `${instanceId}.json`);
31
+ const now = new Date();
32
+ utimesSync(fp, now, now);
33
+ }
34
+ catch (err) {
35
+ // File may not exist yet (no messages ever appended) or perms problem.
36
+ // Best-effort: the agent will catch up on the next message_send / scan.
37
+ log.debug({ err, swarmId, instanceId }, "inbox touch failed (best-effort)");
38
+ }
39
+ }
40
+ }
41
+ //# sourceMappingURL=inbox-touch-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-touch-relay.js","sourceRoot":"","sources":["../src/inbox-touch-relay.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC,CAAC;AAErE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAEpC,OAAO,CAAC,OAAe,EAAE,OAAe,EAAE,UAAkB;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CACb,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAC/B,QAAQ,EACR,OAAO,EACP,SAAS,EACT,GAAG,UAAU,OAAO,CACrB,CAAC;YACF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uEAAuE;YACvE,wEAAwE;YACxE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,kCAAkC,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=log-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-setup.d.ts","sourceRoot":"","sources":["../src/log-setup.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ // Side-effect module: must be the FIRST import in mcp-server's entry.
2
+ // ESM hoists all `import` statements before any non-import code, so we can't
3
+ // set this env var inline in server.ts and expect the logger module to see
4
+ // it at load time. Importing this module as the very first import ensures
5
+ // the env var is set before @mclawnet/logger runs its pino() initializer.
6
+ process.env.CLAWNET_LOG_STDERR = "1";
7
+ export {};
8
+ //# sourceMappingURL=log-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-setup.js","sourceRoot":"","sources":["../src/log-setup.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,6EAA6E;AAC7E,2EAA2E;AAC3E,0EAA0E;AAC1E,0EAA0E;AAC1E,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,GAAG,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ import "./log-setup.js";
3
3
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAOA,OAAO,gBAAgB,CAAC"}
package/dist/server.js CHANGED
@@ -1,4 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ // MCP protocol uses stdout exclusively for JSON-RPC frames. Logging to
3
+ // stdout corrupts the protocol stream and causes the client (codex's rmcp,
4
+ // claude-code's MCP client) to fail with parse errors / "Transport closed".
5
+ // The log-setup module sets CLAWNET_LOG_STDERR=1 — it MUST be the first
6
+ // import so the env var is in place before @mclawnet/logger initializes
7
+ // pino (ESM hoists all imports above non-import statements).
8
+ import "./log-setup.js";
2
9
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
10
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
11
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
@@ -7,7 +14,9 @@ import { join } from "node:path";
7
14
  import { createLogger } from "@mclawnet/logger";
8
15
  import { createEmbeddingProviders, EmbeddingService, initDatabase, MemoryStore, } from "@mclawnet/memory";
9
16
  import { SkillStore, EvolutionPipeline } from "@mclawnet/skill-manager";
17
+ import { WakeupScheduler, WatchManager } from "@mclawnet/swarm";
10
18
  import { getAllToolDefinitions, routeToolCall } from "./tools/index.js";
19
+ import { InboxTouchRelay } from "./inbox-touch-relay.js";
11
20
  const log = createLogger({ module: "mcp-server" });
12
21
  // Two distinct roots:
13
22
  // homeDir — user home (no `.clawnet` suffix). TaskStore/InboxStore append
@@ -33,6 +42,87 @@ const context = {
33
42
  inbox: { rootDir: homeDir },
34
43
  planReview: { rootDir: homeDir },
35
44
  };
45
+ // === Self-wakeup wiring (M5 Task 7) ===
46
+ //
47
+ // The MCP server lives in a stdio subprocess (one per LLM session) while the
48
+ // agent — which owns the real InboxRelay and runs an InboxWatcher on the
49
+ // inbox dir — lives in a sibling process. Same-process injection is therefore
50
+ // impossible. The fix:
51
+ // 1. Construct WakeupScheduler + WatchManager inside this process.
52
+ // 2. Wire them into the inbox tool context.
53
+ // 3. When a timer/watch fires, the cross-process touch-relay updates the
54
+ // recipient's inbox file mtime; the agent's InboxWatcher catches the fs
55
+ // event (50ms debounce) and runs its normal InboxRelay.deliver pass,
56
+ // which picks up the newly-deliverable message (notBefore <= now).
57
+ //
58
+ // The scheduler / watchManager from @mclawnet/swarm only know (swarmId,
59
+ // instanceId); the touch-relay also needs workDir to resolve the inbox file
60
+ // path. We keep a small in-process registry mapping (s,i)→workDir, populated
61
+ // at register time by the wrapper. It can grow indefinitely for distinct
62
+ // (s,i) keys but is bounded by the MCP server's process lifetime (single LLM
63
+ // session) — acceptable for v1.
64
+ const touchRelay = new InboxTouchRelay(homeDir);
65
+ const workdirRegistry = new Map();
66
+ const registryKey = (s, i) => `${s}::${i}`;
67
+ const wakeupScheduler = new WakeupScheduler({
68
+ deliver: (swarmId, instanceId) => {
69
+ const key = registryKey(swarmId, instanceId);
70
+ const workDir = workdirRegistry.get(key);
71
+ if (!workDir) {
72
+ // Should not happen — wakeup_after always populates the registry before
73
+ // register. Log so a future eviction policy can be debugged.
74
+ log.warn({ swarmId, instanceId }, "wakeup deliver: no workDir in registry");
75
+ return;
76
+ }
77
+ touchRelay.deliver(workDir, swarmId, instanceId);
78
+ // Wakeup is single-fire — drop the registry entry to bound growth.
79
+ // (Re-registration by a new wakeup_after call will re-populate.)
80
+ workdirRegistry.delete(key);
81
+ },
82
+ });
83
+ const watchManager = new WatchManager();
84
+ context.inbox.scheduler = {
85
+ register: (swarmId, instanceId, notBefore, workDir) => {
86
+ workdirRegistry.set(registryKey(swarmId, instanceId), workDir);
87
+ wakeupScheduler.register(swarmId, instanceId, notBefore);
88
+ },
89
+ countForInstance: (s, i) => wakeupScheduler.countForInstance(s, i),
90
+ };
91
+ context.inbox.watchManager = {
92
+ register: (reg) => {
93
+ workdirRegistry.set(registryKey(reg.swarmId, reg.instanceId), reg.projectRoot);
94
+ watchManager.register(reg);
95
+ },
96
+ countForInstance: (s, i) => watchManager.countForInstance(s, i),
97
+ unregister: (s, i, w) => {
98
+ watchManager.unregister(s, i, w);
99
+ // I3: when the last watch for (s,i) is dropped, prune the registry
100
+ // entry too — long-lived sessions with many distinct (s,i) pairs
101
+ // otherwise grow monotonically. Wakeups re-set the entry on demand;
102
+ // we don't need to worry about racing with an in-flight wakeup
103
+ // because the registry entry is single-fire (wakeup deliver also
104
+ // deletes it on fire).
105
+ if (watchManager.countForInstance(s, i) === 0) {
106
+ workdirRegistry.delete(registryKey(s, i));
107
+ }
108
+ },
109
+ unwatchByInstance: (s, i) => {
110
+ watchManager.unwatchByInstance(s, i);
111
+ workdirRegistry.delete(registryKey(s, i));
112
+ },
113
+ };
114
+ context.inbox.relay = {
115
+ deliver: (swarmId, instanceId) => {
116
+ const workDir = workdirRegistry.get(registryKey(swarmId, instanceId));
117
+ if (workDir)
118
+ touchRelay.deliver(workDir, swarmId, instanceId);
119
+ },
120
+ };
121
+ // Restart safety: timers don't survive process exit. We intentionally do NOT
122
+ // call WakeupScheduler.restoreFromInbox here — mcp-server lifetime equals the
123
+ // LLM session, so restoring across sessions would pile up stale timers. The
124
+ // agent-process restart story is a separate concern (it owns InboxRelay and
125
+ // can re-scan inboxes on its own startup).
36
126
  const server = new Server({ name: "clawnet-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
37
127
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
38
128
  tools: getAllToolDefinitions(),
@@ -46,6 +136,18 @@ await server.connect(transport);
46
136
  log.info("ClawNet MCP server connected via stdio");
47
137
  function cleanup() {
48
138
  log.info("ClawNet MCP server shutting down");
139
+ try {
140
+ wakeupScheduler.dispose();
141
+ }
142
+ catch {
143
+ // ignore
144
+ }
145
+ try {
146
+ watchManager.dispose();
147
+ }
148
+ catch {
149
+ // ignore
150
+ }
49
151
  try {
50
152
  db.close();
51
153
  }
@@ -53,6 +155,17 @@ function cleanup() {
53
155
  // ignore
54
156
  }
55
157
  }
158
+ // `process.on("exit")` runs cleanup at natural exit too. SIGINT/SIGTERM
159
+ // handlers below call cleanup and then exit; the "exit" handler is a no-op
160
+ // the second time around (dispose / db.close are idempotent enough).
161
+ //
162
+ // We do NOT try to drain in-flight `routeToolCall` work before exiting —
163
+ // MCP protocol over stdio has no graceful-close handshake exposed via the
164
+ // SDK at the time of writing, and a stuck handler would block shutdown
165
+ // indefinitely. The trade-off: a tool call interrupted at the wrong instant
166
+ // may leave a partially-written inbox file. InboxStore uses proper-lockfile +
167
+ // integer-replace writes, so the file stays valid JSON; the worst case is
168
+ // a missing message that the caller will need to retry.
56
169
  process.on("exit", cleanup);
57
170
  process.on("SIGINT", () => {
58
171
  cleanup();
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -16,9 +16,54 @@ export interface InboxToolContext {
16
16
  * agent is woken immediately. Failures are swallowed (best-effort).
17
17
  */
18
18
  relay?: InboxRelayLike;
19
+ /**
20
+ * Optional wakeup scheduler. When present, `wakeup_after` registers a timer
21
+ * after writing the deferred inbox message so it fires in-process when the
22
+ * notBefore time arrives. Without this, the message still lands on disk and
23
+ * will be picked up on the next inbox scan / restart restore.
24
+ */
25
+ scheduler?: {
26
+ /**
27
+ * `workDir` is required by the MCP server's wrapper, which keeps a
28
+ * (swarmId,instanceId)→workDir registry so the cross-process touch-relay
29
+ * can resolve the inbox file path when the timer fires. The underlying
30
+ * @mclawnet/swarm WakeupScheduler still takes only 3 args; the extra
31
+ * parameter is consumed by the wrapper before delegating.
32
+ */
33
+ register(swarmId: string, instanceId: string, notBefore: number, workDir: string): void;
34
+ /** I4 caps: per-instance active timer count, used to reject before write. */
35
+ countForInstance?(swarmId: string, instanceId: string): number;
36
+ };
37
+ /**
38
+ * Optional fs-watch manager. When present, `watch_path` registers a watch
39
+ * whose `onTrigger` writes an inbox message and (best-effort) wakes the
40
+ * recipient via `relay.deliver`. Without it, `watch_path` returns isError.
41
+ */
42
+ watchManager?: {
43
+ register(reg: WatchRegistrationLike): void;
44
+ unregister(swarmId: string, instanceId: string, watchId: string): void;
45
+ unwatchByInstance(swarmId: string, instanceId: string): void;
46
+ /** I4 caps: per-instance active watch count, used to reject before register. */
47
+ countForInstance?(swarmId: string, instanceId: string): number;
48
+ };
49
+ }
50
+ /**
51
+ * Minimal structural shape for a WatchManager registration. Kept local (not
52
+ * imported from @mclawnet/swarm) to keep the contextual coupling loose — the
53
+ * router wires in the real type at start time.
54
+ */
55
+ export interface WatchRegistrationLike {
56
+ swarmId: string;
57
+ instanceId: string;
58
+ watchId: string;
59
+ projectRoot: string;
60
+ includeGlobs: string[];
61
+ ignoreGlobs: string[];
62
+ debounceMs: number;
63
+ onTrigger: (matchedPath: string) => void | Promise<void>;
19
64
  }
20
65
  export declare const INBOX_TOOL_NAMES: Set<string>;
21
- export declare function getInboxToolDefinitions(): {
66
+ export declare function getInboxToolDefinitions(): ({
22
67
  name: string;
23
68
  description: string;
24
69
  inputSchema: {
@@ -60,10 +105,128 @@ export declare function getInboxToolDefinitions(): {
60
105
  type: string[];
61
106
  description: string;
62
107
  };
108
+ instanceId?: undefined;
109
+ seconds?: undefined;
110
+ payload?: undefined;
111
+ includeGlobs?: undefined;
112
+ ignoreGlobs?: undefined;
113
+ debounceMs?: undefined;
114
+ watchId?: undefined;
115
+ };
116
+ required: string[];
117
+ };
118
+ } | {
119
+ name: string;
120
+ description: string;
121
+ inputSchema: {
122
+ type: "object";
123
+ properties: {
124
+ workDir: {
125
+ type: string;
126
+ description: string;
127
+ };
128
+ swarmId: {
129
+ type: string;
130
+ description: string;
131
+ };
132
+ instanceId: {
133
+ type: string;
134
+ description: string;
135
+ };
136
+ seconds: {
137
+ type: string;
138
+ exclusiveMinimum: number;
139
+ maximum: number;
140
+ description: string;
141
+ };
142
+ payload: {
143
+ type: string;
144
+ description: string;
145
+ };
146
+ type: {
147
+ type: string;
148
+ description: string;
149
+ };
150
+ from: {
151
+ type: string;
152
+ description: string;
153
+ };
154
+ to?: undefined;
155
+ data?: undefined;
156
+ taskId?: undefined;
157
+ expectedStatus?: undefined;
158
+ expectedOwner?: undefined;
159
+ includeGlobs?: undefined;
160
+ ignoreGlobs?: undefined;
161
+ debounceMs?: undefined;
162
+ watchId?: undefined;
163
+ };
164
+ required: string[];
165
+ };
166
+ } | {
167
+ name: string;
168
+ description: string;
169
+ inputSchema: {
170
+ type: "object";
171
+ properties: {
172
+ workDir: {
173
+ type: string;
174
+ description: string;
175
+ };
176
+ swarmId: {
177
+ type: string;
178
+ description?: undefined;
179
+ };
180
+ instanceId: {
181
+ type: string;
182
+ description: string;
183
+ };
184
+ includeGlobs: {
185
+ type: string;
186
+ items: {
187
+ type: string;
188
+ };
189
+ minItems: number;
190
+ description: string;
191
+ };
192
+ payload: {
193
+ type: string;
194
+ description: string;
195
+ };
196
+ ignoreGlobs: {
197
+ type: string;
198
+ items: {
199
+ type: string;
200
+ };
201
+ description: string;
202
+ };
203
+ debounceMs: {
204
+ type: string;
205
+ minimum: number;
206
+ description: string;
207
+ };
208
+ type: {
209
+ type: string;
210
+ description: string;
211
+ };
212
+ from: {
213
+ type: string;
214
+ description: string;
215
+ };
216
+ watchId: {
217
+ type: string;
218
+ description: string;
219
+ };
220
+ to?: undefined;
221
+ data?: undefined;
222
+ taskId?: undefined;
223
+ expectedStatus?: undefined;
224
+ expectedOwner?: undefined;
225
+ seconds?: undefined;
63
226
  };
64
227
  required: string[];
65
228
  };
66
- }[];
229
+ })[];
67
230
  export declare function handleInboxToolCall(name: string, args: Record<string, unknown>, context: InboxToolContext): Promise<{
68
231
  content: Array<{
69
232
  type: "text";
@@ -1 +1 @@
1
- {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/tools/inbox.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,aAA4B,CAAC;AAE1D,wBAAgB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+BtC;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAoBhF"}
1
+ {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/tools/inbox.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE;QACV;;;;;;WAMG;QACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACxF,6EAA6E;QAC7E,gBAAgB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;KAChE,CAAC;IACF;;;;OAIG;IACH,YAAY,CAAC,EAAE;QACb,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CAAC;QAC3C,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvE,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7D,gFAAgF;QAChF,gBAAgB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;KAChE,CAAC;CACH;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AAED,eAAO,MAAM,gBAAgB,aAA0D,CAAC;AAcxF,wBAAgB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkFtC;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAwBhF"}