@cotal-ai/connector-codex 0.1.4 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.d.ts CHANGED
@@ -1,2 +1,19 @@
1
- export {};
1
+ import { type MeshAgent, type AgentConfig } from "@cotal-ai/connector-core";
2
+ /** The env var the codex child reads the bearer token from (`mcp_servers.cotal.bearer_token_env_var`). */
3
+ export declare const MCP_TOKEN_ENV = "COTAL_MCP_TOKEN";
4
+ /** The MCP server name, and therefore the `mcp_servers.<name>` config prefix. */
5
+ export declare const MCP_SERVER_NAME = "cotal";
6
+ export interface CotalMcpEndpoint {
7
+ /** `http://127.0.0.1:<port>/mcp` — what `mcp_servers.cotal.url` points at. */
8
+ url: string;
9
+ /** The bearer token, passed to the child by env var NAME (see {@link MCP_TOKEN_ENV}). */
10
+ token: string;
11
+ close(): Promise<void>;
12
+ }
13
+ /**
14
+ * Build and serve the cotal_* tools. The returned URL/token go into the codex child's config
15
+ * and env. That token is what keeps other OS users and off-box callers out; it is not a barrier
16
+ * to a same-uid sibling that can read the child's environment (see the header).
17
+ */
18
+ export declare function startCotalMcp(agent: MeshAgent, config: AgentConfig, log: (m: string) => void): Promise<CotalMcpEndpoint>;
2
19
  //# sourceMappingURL=mcp.d.ts.map
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAmB,MAAM,0BAA0B,CAAC;AAE7G,0GAA0G;AAC1G,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAC/C,iFAAiF;AACjF,eAAO,MAAM,eAAe,UAAU,CAAC;AAUvC,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAC;IACZ,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAsBD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA6J3B"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Codex transcript mirror — publishes the agent's OWN thread output to the per-agent
3
+ * `tr-<name>` channel (assistant text in full, commands/tool calls as one-liners,
4
+ * reasoning omitted), at parity with the Claude Code and OpenCode mirrors.
5
+ *
6
+ * EVENT-DRIVEN off the app-server notification stream the host already consumes:
7
+ * • observe(item) ← item/completed: condense the item NOW and buffer its lines;
8
+ * • flush() ← turn end: publish the turn's settled lines, then clear.
9
+ * Snapshot-then-clear before the await means a duplicate turn-end can't republish.
10
+ * Best-effort at the publish boundary: the host keeps a transport error OFF the turn
11
+ * loop (logged, never wedging the agent); durability/replay is the channel's job.
12
+ */
13
+ import type { MeshAgent } from "@cotal-ai/connector-core";
14
+ import type { ThreadItem } from "./app-server.js";
15
+ export interface TranscriptMirror {
16
+ /** item/completed → buffer the item's condensed lines (preview-truncated at buffer time). */
17
+ observe(item: ThreadItem): void;
18
+ /** turn end → publish the turn's lines to the channel, then clear. */
19
+ flush(): Promise<void>;
20
+ }
21
+ export declare function createTranscriptMirror(agent: MeshAgent, channel: string): TranscriptMirror;
22
+ //# sourceMappingURL=transcript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuDlD,MAAM,WAAW,gBAAgB;IAC/B,6FAA6F;IAC7F,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,sEAAsE;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAY1F"}
package/dist/tui.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The real Codex TUI, attached to the agent's mesh thread.
3
+ *
4
+ * `codex resume --remote <ws-url> <threadId>` connects Codex's own interactive app to the
5
+ * app-server the host is already driving, and REJOINS the running thread rather than starting a
6
+ * private one. That is what makes `cotal spawn --agent codex` land you in Codex proper: the mesh
7
+ * turns the host drives render here as they happen, and anything typed here is a real user turn
8
+ * on the same thread, with the cotal_* tools still routed back to the host's mesh endpoint.
9
+ *
10
+ * The TUI owns the terminal (stdio inherited), so the host must not write to it — see host.ts,
11
+ * which redirects its own logging to a file for exactly this reason.
12
+ */
13
+ import { type ChildProcess } from "node:child_process";
14
+ export interface TuiOpts {
15
+ /** `ws://127.0.0.1:<port>` from the driver's {@link import("./app-server.js").RemoteEndpoint}. */
16
+ url: string;
17
+ token: string;
18
+ /** The thread the host started and drives — the TUI rejoins THIS one. */
19
+ threadId: string;
20
+ /** The agent's private CODEX_HOME, so the TUI reads the managed config, never the operator's. */
21
+ codexHome: string;
22
+ cwd: string;
23
+ bin?: string;
24
+ }
25
+ /**
26
+ * Launch the TUI on this process's terminal. The caller owns the returned child: its exit means
27
+ * the operator quit the session, which the host treats as a cooperative shutdown.
28
+ */
29
+ export declare function launchTui(opts: TuiOpts): ChildProcess;
30
+ //# sourceMappingURL=tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAM9D,MAAM,WAAW,OAAO;IACtB,kGAAkG;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAmBrD"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-codex",
3
- "version": "0.1.4",
3
+ "description": "Cotal connector for OpenAI Codex: a host-mode peer driving codex app-server, with Codex's own TUI attached and the cotal_* tools served over a loopback MCP endpoint.",
4
+ "version": "0.16.0",
4
5
  "license": "Apache-2.0",
5
6
  "repository": {
6
7
  "type": "git",
@@ -16,16 +17,18 @@
16
17
  "import": "./dist/index.js"
17
18
  }
18
19
  },
19
- "dependencies": {
20
- "@modelcontextprotocol/sdk": "^1.29.0",
21
- "tsx": "^4.22.4",
22
- "@cotal-ai/connector-core": "0.2.0"
23
- },
24
20
  "peerDependencies": {
25
- "@cotal-ai/core": "0.1.3"
21
+ "@cotal-ai/core": ">=0.1.0"
26
22
  },
27
23
  "devDependencies": {
28
- "@cotal-ai/core": "0.1.3"
24
+ "@modelcontextprotocol/sdk": "^1.29.0",
25
+ "@types/ws": "^8.18.1",
26
+ "esbuild": "^0.28.0",
27
+ "tsx": "^4.22.4",
28
+ "ws": "^8.21.0",
29
+ "zod": "^4.4.3",
30
+ "@cotal-ai/core": "0.16.0",
31
+ "@cotal-ai/connector-core": "0.16.0"
29
32
  },
30
33
  "files": [
31
34
  "dist"
@@ -35,6 +38,7 @@
35
38
  },
36
39
  "scripts": {
37
40
  "typecheck": "tsc -p tsconfig.json --noEmit",
38
- "build": "tsc -p tsconfig.json"
41
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json --emitDeclarationOnly && pnpm run bundle",
42
+ "bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/index.js --external:@cotal-ai/core && esbuild src/host-main.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/host.js --banner:js=\"import { createRequire as __cotalCreateRequire } from 'node:module'; const require = __cotalCreateRequire(import.meta.url);\""
39
43
  }
40
44
  }
package/dist/extension.js DELETED
@@ -1,57 +0,0 @@
1
- import { fileURLToPath } from "node:url";
2
- import { registry } from "@cotal-ai/core";
3
- /** The MCP server runs straight from source via tsx (Codex has no plugin copy-install, so
4
- * there's no build step) — both paths resolved relative to this file. */
5
- const TSX = fileURLToPath(new URL("../node_modules/.bin/tsx", import.meta.url));
6
- const MCP_ENTRY = fileURLToPath(new URL("./mcp.ts", import.meta.url));
7
- /** A TOML basic-string literal. Escapes the only interpolated values (absolute paths + identity)
8
- * so a value containing a quote or backslash can't break — or inject into — the `-c` override. */
9
- const toml = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
10
- /**
11
- * The Codex connector: launches `codex` with the cotal MCP server injected via `-c` overrides,
12
- * so the session joins the mesh as a lateral peer. Codex is **pull-only** — it sandboxes
13
- * lifecycle hooks (they can't reach the connector's control socket), so there are no hooks: the
14
- * agent reads its inbox with `cotal_inbox` and reports presence with `cotal_status`. The overrides
15
- * live in memory only — the operator's `~/.codex` (auth, model, their own servers) is never
16
- * written. Self-registers on import; the manager resolves it by agent type "codex".
17
- */
18
- export const codexConnector = {
19
- kind: "connector",
20
- name: "codex",
21
- buildLaunch(opts) {
22
- const env = { COTAL_SPACE: opts.space, COTAL_NAME: opts.name };
23
- if (opts.role)
24
- env.COTAL_ROLE = opts.role;
25
- if (opts.servers)
26
- env.COTAL_SERVERS = opts.servers;
27
- // Codex does not forward custom env to MCP servers, so identity goes in the server's `env`
28
- // table (escaped). approval_policy + sandbox make a spawned agent autonomous — it would
29
- // otherwise hang on the first approval prompt; default_tools_approval_mode auto-approves the
30
- // cotal tools so the agent can use the mesh without a human in the loop.
31
- const args = [
32
- "-c", `mcp_servers.cotal.command=${toml(TSX)}`,
33
- "-c", `mcp_servers.cotal.args=[${toml(MCP_ENTRY)}]`,
34
- "-c", `mcp_servers.cotal.default_tools_approval_mode="auto"`,
35
- "-c", `mcp_servers.cotal.env.COTAL_SPACE=${toml(opts.space)}`,
36
- "-c", `mcp_servers.cotal.env.COTAL_NAME=${toml(opts.name)}`,
37
- "-c", `approval_policy="never"`,
38
- "-c", `sandbox_mode="workspace-write"`,
39
- ];
40
- if (opts.role)
41
- args.push("-c", `mcp_servers.cotal.env.COTAL_ROLE=${toml(opts.role)}`);
42
- if (opts.servers)
43
- args.push("-c", `mcp_servers.cotal.env.COTAL_SERVERS=${toml(opts.servers)}`);
44
- // Identity + auth ride in the server's env table too (Codex forwards no process env to MCP
45
- // servers): the provisioned id, the minted creds, and the agent file. Without COTAL_CREDS the
46
- // endpoint can't authenticate to an auth-by-default mesh, so the agent would never join.
47
- if (opts.id)
48
- args.push("-c", `mcp_servers.cotal.env.COTAL_ID=${toml(opts.id)}`);
49
- if (opts.creds)
50
- args.push("-c", `mcp_servers.cotal.env.COTAL_CREDS=${toml(opts.creds)}`);
51
- if (opts.configPath)
52
- args.push("-c", `mcp_servers.cotal.env.COTAL_AGENT_FILE=${toml(opts.configPath)}`);
53
- return { command: "codex", args, env };
54
- },
55
- };
56
- registry.register(codexConnector);
57
- //# sourceMappingURL=extension.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAoD,MAAM,gBAAgB,CAAC;AAE5F;0EAC0E;AAC1E,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChF,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtE;mGACmG;AACnG,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAEzF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,OAAO;IACb,WAAW,CAAC,IAAgB;QAC1B,MAAM,GAAG,GAA2B,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACvF,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,CAAC,OAAO;YAAE,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnD,2FAA2F;QAC3F,wFAAwF;QACxF,6FAA6F;QAC7F,yEAAyE;QACzE,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,6BAA6B,IAAI,CAAC,GAAG,CAAC,EAAE;YAC9C,IAAI,EAAE,2BAA2B,IAAI,CAAC,SAAS,CAAC,GAAG;YACnD,IAAI,EAAE,sDAAsD;YAC5D,IAAI,EAAE,qCAAqC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YAC7D,IAAI,EAAE,oCAAoC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC3D,IAAI,EAAE,yBAAyB;YAC/B,IAAI,EAAE,gCAAgC;SACvC,CAAC;QACF,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oCAAoC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtF,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,uCAAuC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/F,2FAA2F;QAC3F,8FAA8F;QAC9F,yFAAyF;QACzF,IAAI,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,kCAAkC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,qCAAqC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzF,IAAI,IAAI,CAAC,UAAU;YACjB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,0CAA0C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACrF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;CACF,CAAC;AAEF,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC,CAAC,iDAAiD"}
package/dist/mcp.js DELETED
@@ -1,55 +0,0 @@
1
- /**
2
- * Cotal Codex connector — MCP (stdio) server.
3
- *
4
- * Turns the Codex session that launches it into a first-class Cotal mesh peer: presence + the
5
- * shared cotal_* tools (from @cotal-ai/connector-core). Codex is **pull-only** — it sandboxes
6
- * lifecycle hooks (they can't reach a control socket), so there is no hook relay: the agent reads
7
- * its inbox with cotal_inbox and reports presence with cotal_status. Identity comes from `COTAL_*`
8
- * env (set by the connector's MCP `env` table).
9
- *
10
- * stdio transport owns stdout for JSON-RPC — ALL diagnostics go to stderr.
11
- */
12
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
- import { configFromEnv, feedbackLine, hasIdentity, laneLine, MeshAgent, registerCotalTools } from "@cotal-ai/connector-core";
15
- async function main() {
16
- // No identity → not a launcher-spawned agent. Stay inert so a stray `codex` with the cotal MCP
17
- // server registered can't join the mesh as an unmanaged peer.
18
- if (!hasIdentity()) {
19
- process.stderr.write("[cotal-connector] no COTAL_NAME — not a managed session; staying off the mesh\n");
20
- return;
21
- }
22
- const config = configFromEnv();
23
- const agent = new MeshAgent(config);
24
- agent.start(); // background connect with retry — never blocks tool serving
25
- const server = new McpServer({ name: "cotal", version: "0.0.0" }, {
26
- instructions: `You are connected to the Cotal mesh as "${config.name}"` +
27
- `${config.role ? ` (role: ${config.role})` : ""} in space "${config.space}". ` +
28
- laneLine(config) +
29
- feedbackLine(config) +
30
- `Other agents coordinate with you here as lateral peers. Read messages others have sent ` +
31
- `you with cotal_inbox (check it when you start and between tasks). When a reply is ` +
32
- `warranted, respond with cotal_dm (a peer), cotal_send (a channel), or cotal_anycast (a ` +
33
- `role). Use cotal_roster to see who is present, and cotal_status to report what you are ` +
34
- `doing (working/idle) so peers can see your state. No need to reply in a channel if not addressed directly, unless you have something worthwhile to add, no need for courtesy and politeness in your responses.`,
35
- });
36
- registerCotalTools(server, agent, config, "codex");
37
- const shutdown = async () => {
38
- try {
39
- await agent.stop();
40
- }
41
- finally {
42
- process.exit(0);
43
- }
44
- };
45
- process.on("SIGINT", () => void shutdown());
46
- process.on("SIGTERM", () => void shutdown());
47
- const transport = new StdioServerTransport();
48
- await server.connect(transport);
49
- process.stderr.write(`[cotal-connector] MCP ready (stdio, pull-only) — space="${config.space}" name="${config.name}"${config.role ? ` role="${config.role}"` : ""}\n`);
50
- }
51
- main().catch((e) => {
52
- process.stderr.write(`[cotal-connector] fatal: ${e.stack ?? String(e)}\n`);
53
- process.exit(1);
54
- });
55
- //# sourceMappingURL=mcp.js.map
package/dist/mcp.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE7H,KAAK,UAAU,IAAI;IACjB,+FAA+F;IAC/F,8DAA8D;IAC9D,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;QACxG,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,4DAA4D;IAE3E,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,EACnC;QACE,YAAY,EACV,2CAA2C,MAAM,CAAC,IAAI,GAAG;YACzD,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,cAAc,MAAM,CAAC,KAAK,KAAK;YAC9E,QAAQ,CAAC,MAAM,CAAC;YAChB,YAAY,CAAC,MAAM,CAAC;YACpB,yFAAyF;YACzF,oFAAoF;YACpF,yFAAyF;YACzF,yFAAyF;YACzF,gNAAgN;KACnN,CACF,CAAC;IAEF,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnD,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAE7C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2DAA2D,MAAM,CAAC,KAAK,WAAW,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CACjJ,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA6B,CAAW,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}