@moikapy/lich 0.6.0 → 0.7.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +75 -1
  2. package/README.md +59 -7
  3. package/dist/{chunk-JC2G3XH2.js → chunk-CVX7LZWC.js} +2 -2
  4. package/dist/chunk-PZNYVGD4.js +58 -0
  5. package/dist/chunk-PZNYVGD4.js.map +1 -0
  6. package/dist/{chunk-7HLVKVIG.js → chunk-WNFBIX4E.js} +1344 -162
  7. package/dist/chunk-WNFBIX4E.js.map +1 -0
  8. package/dist/cli.js +246 -18
  9. package/dist/cli.js.map +1 -1
  10. package/dist/{gateway-RJFZJEUZ.js → gateway-44QTIJTJ.js} +108 -49
  11. package/dist/gateway-44QTIJTJ.js.map +1 -0
  12. package/dist/index.d.ts +288 -154
  13. package/dist/index.js +5 -3
  14. package/dist/{tui-LOUJVZ6A.js → tui-MEJGEILU.js} +25 -10
  15. package/dist/tui-MEJGEILU.js.map +1 -0
  16. package/docs/.vitepress/config.mts +4 -0
  17. package/docs/architecture/overview.md +30 -18
  18. package/docs/architecture/plugins.md +1 -1
  19. package/docs/architecture/tools.md +36 -4
  20. package/docs/getting-started.md +7 -6
  21. package/docs/index.md +5 -4
  22. package/docs/user-guide/cli.md +21 -8
  23. package/docs/user-guide/games.md +1 -1
  24. package/docs/user-guide/gateway.md +70 -16
  25. package/docs/user-guide/godot.md +3 -1
  26. package/docs/user-guide/library.md +4 -2
  27. package/docs/user-guide/plugins.md +2 -2
  28. package/docs/user-guide/redot.md +93 -0
  29. package/docs/user-guide/tui.md +2 -2
  30. package/examples/game_bridge/README.md +2 -0
  31. package/optional-mcps/godot/manifest.json +6 -0
  32. package/optional-mcps/redot/manifest.json +18 -0
  33. package/package.json +2 -1
  34. package/dist/chunk-6M6OAQGN.js +0 -17
  35. package/dist/chunk-6M6OAQGN.js.map +0 -1
  36. package/dist/chunk-7HLVKVIG.js.map +0 -1
  37. package/dist/gateway-RJFZJEUZ.js.map +0 -1
  38. package/dist/tui-LOUJVZ6A.js.map +0 -1
  39. /package/dist/{chunk-JC2G3XH2.js.map → chunk-CVX7LZWC.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,80 @@
1
1
  # Changelog
2
2
 
3
- ## 0.6.0 (unreleased)
3
+ ## 0.7.1
4
+
5
+ - close agent-core review must-fixes A-1–A-4: multi-turn runs stop
6
+ duplicating history, tool pairs survive compression and gateway history
7
+ caps, and a mid-call abort becomes `stopped_reason: aborted` with the
8
+ abort signal reaching in-flight tools.
9
+ - harden the webhook gateway (G-1/G-2/G-3/G-5): binds to loopback by
10
+ default and requires a token when exposed, defaults public platforms
11
+ (telegram/discord/twitch) to deny with a configurable allowlist plus a
12
+ reduced safe toolset, catches telegram/discord reply send failures
13
+ instead of crashing the run, and forces `platform=webhook` on the HTTP
14
+ adapter.
15
+ - close MCP exit (M-1), empty Anthropic text, and env provider fallback:
16
+ one-shot/chat/TUI/gateway runs call `Agent.close()` so stdio MCP
17
+ sessions release; node children are still `unref`'d so the event loop
18
+ can drain (bun keeps the child attached — see below). an empty
19
+ Anthropic text block no longer 400s the session permanently, and
20
+ mcp-only project configs no longer shadow `LICH_MODEL` / env providers.
21
+ - close tools must-fixes S-1–S-5: file writes/edits resolve realpath so
22
+ symlink escapes are confined, `fetch_url`/`http_request` block private
23
+ and loopback URLs, `.lich/config.json` and `.env` are forbidden write
24
+ targets, terminal child env is scrubbed of provider secrets, and
25
+ dash-leading `run_tests` filters are rejected so they cannot open the
26
+ commit gate. `http_request` also strips IPv6 brackets before SSRF IP
27
+ classification so `[::1]` literals are not skipped, and asserts headers
28
+ through `Headers` after the `safe_fetch` merge.
29
+ - isolate usage per run (A-5) and memoize MCP attach (A-6): concurrent
30
+ `Agent.run` calls no longer mix `usage_total`, and attach races can
31
+ neither skip nor permanently fail.
32
+ - TUI: ignore message submit while a run is in flight (U-1), and walk the
33
+ newest-first recall ring so Up moves to older entries instead of
34
+ clamping on the newest (U-2).
35
+ - pin outbound HTTP: `fetch_url` and `http_request` keep the https
36
+ hostname for TLS/SNI and the `Host` header while `safe_fetch` pins the
37
+ connect to a vetted public IP through a custom DNS `lookup`, and
38
+ re-validates every redirect hop. the operator opt-out is exact:
39
+ `LICH_ALLOW_PRIVATE_URLS=1`; unset or any other value is fail-closed
40
+ (private/loopback URLs blocked).
41
+ - harden `grep_files`: the directory walk skips symbolic links (same
42
+ skip path as `SKIP_DIRS`), and every candidate read runs
43
+ `assert_file_tool_access`, so `.lich/config.json` is denied with
44
+ `forbidden_path: .lich/config.json`.
45
+ - twitch gateway: `PRIVMSG` matching is anchored (`^:... PRIVMSG #...
46
+ :...$` after the optional tags strip), so `USERNOTICE` and
47
+ `WHISPER` lines are not chat and cannot spoof the allowlist.
48
+ - bun stdio MCP children are no longer `unref`'d: one-shot and
49
+ short-lived runs wait for the MCP answer instead of letting the child
50
+ detach and exit early.
51
+ - add CI (tsc + vitest on Node 20/22), sync the 0.7.0 user docs with this
52
+ tree, and make `edit_file` treat `$` sequences literally while allowing
53
+ an empty `new_string` (#57).
54
+ - sync docs/architecture with the outbound-HTTP pin, grep hardening,
55
+ twitch anchor, and bun MCP exit changes (#61).
56
+ - add a manual Release workflow: Actions → Release → Run workflow (from
57
+ `main`) with a `patch|minor|major` bump runs `bun release`, then
58
+ publishes the packed tarball to npm with `NPM_TOKEN`. maintainer
59
+ plumbing, not a runtime change (#62).
60
+
61
+ ## 0.7.0
62
+
63
+ - add a general MCP client. `mcp_servers` is a closed record of named
64
+ stdio or loopback-http entries, default off. tool names are
65
+ `mcp_<server>_<tool>`. `tools_enabled: []` drops them. the commander
66
+ persona does not copy `mcp_servers`. redot is a catalog entry (local
67
+ `redot` binary, `--headless --mcp-server --path <project>`, five
68
+ upstream controllers, no execute). godot has no official server; lich
69
+ does not download a community addon. play stays the webhook and
70
+ game_bridge, the opposite direction. see docs/user-guide/redot.md.
71
+ - add `lich mcp` to list, add, enable, disable, and remove servers.
72
+ add uses the catalog or `--command`/`--url`, stays disabled, and
73
+ updates `.lich/config.json` through the existing writer without
74
+ dropping other keys.
75
+ - sync user docs with this tree. MCP is included in the 0.7.0 package.
76
+
77
+ ## 0.6.0
4
78
 
5
79
  - document a per-persona orchestrator example: one agent per NPC, the
6
80
  webhook `POST /message` shape, and history serialization the game repo
package/README.md CHANGED
@@ -15,7 +15,7 @@ mythology lives in display strings only.
15
15
  | --- | --- | --- |
16
16
  | **phylacteries** | JSONL session files in `.lich/sessions/` — conversations survive process death | This glossary; TUI `/sessions` listing label |
17
17
  | **vessel-hopping** | Provider failover: 429/5xx retried with backoff, then the next provider takes over | This glossary |
18
- | **the lair / wards** | `work_dir` confinement + `path_escape` guardrails | This glossary |
18
+ | **the lair / wards** | `work_dir` confinement + `path_escape` guardrails for file tools. Wards do **not** apply to `terminal` or `run_tests` (shell still runs in `work_dir`; secret env names are scrubbed on spawn). | This glossary |
19
19
  | **lair actions** | Plugin hooks that observe or veto tool calls | This glossary |
20
20
  | **familiars** | Gateway adapters (webhook/telegram/discord/twitch) routing into one shared agent | This glossary |
21
21
  | **spells** | Builtin tools in the registry | This glossary |
@@ -30,10 +30,13 @@ mythology lives in display strings only.
30
30
  | --- | --- |
31
31
  | [Docs home](docs/index.md) | Overview, feature map, and a 60-second quickstart. |
32
32
  | [Getting started](docs/getting-started.md) | Zero-to-first-reply: install, config paths, one-shot, TUI, gateway. |
33
- | [CLI reference](docs/user-guide/cli.md) | All four modes, flags, provider resolution, config schema, recipes. |
33
+ | [CLI reference](docs/user-guide/cli.md) | Modes, flags, provider resolution, config schema, `lich mcp`, recipes. |
34
34
  | [TUI guide](docs/user-guide/tui.md) | Launch, slash commands, status bar, memory semantics. |
35
35
  | [Gateway guide](docs/user-guide/gateway.md) | Webhook/Telegram/Discord/Twitch setup and the webhook API. |
36
36
  | [Library guide](docs/user-guide/library.md) | Embedding: `create_agent`, events, multi-turn history, errors. |
37
+ | [Plugins guide](docs/user-guide/plugins.md) | User tools and hooks, and the self-improvement loop. |
38
+ | [Godot guide](docs/user-guide/godot.md) | The game connects to lich (webhook + `game_bridge`). |
39
+ | [Redot guide](docs/user-guide/redot.md) | lich connects to editor MCP servers. Redot is a catalog entry. |
37
40
  | [Games guide](docs/user-guide/games.md) | Session JSONL as a combat log, and jq recipes over it. |
38
41
  | [Persona example](examples/persona_orchestrator/README.md) | Per-NPC agents the game repo copies. Not a second core. |
39
42
 
@@ -63,7 +66,8 @@ lich gateway webhook
63
66
 
64
67
  The CLI has four modes: **one-shot** (`lich "task"`), **chat**
65
68
  (`lich chat`), **tui** (`lich tui`), and **gateway**
66
- (`lich gateway <platform...>`).
69
+ (`lich gateway <platform...>`). Other commands do not start an agent:
70
+ `lich init`, `lich config`, `lich update`, and `lich mcp`.
67
71
 
68
72
  Or use a JSON config file: `lich --config lich.json "task"` (see
69
73
  `AgentConfig` in `src/agent/config.ts` for the schema).
@@ -97,7 +101,7 @@ snake_case args and are registered under the `builtin` toolset.
97
101
  | `edit_file` | Replace a unique string in a file, with an optional replace-all. |
98
102
  | `list_dir` | List a directory tree iteratively (dirs first, file sizes). |
99
103
  | `terminal` | Run a shell command via `bash -lc` and capture output plus exit code. |
100
- | `grep_files` | Regex search across files, skipping node_modules/.git/dist and binaries. |
104
+ | `grep_files` | Regex search across files, skipping node_modules/.git/dist, symlinks, and binaries; `.lich/config.json` is denied. |
101
105
  | `fetch_url` | GET an http(s) URL and return the body text with a status header. |
102
106
  | `web_search` | Web search via DuckDuckGo's HTML endpoint (no api key). |
103
107
  | `http_request` | Generic HTTP calls (method/headers/body) for REST-ish APIs. |
@@ -113,7 +117,9 @@ snake_case args and are registered under the `builtin` toolset.
113
117
  Customize lich with your own tools and lifecycle hooks: keep a `Plugin`
114
118
  object (`{name, tools?, hooks?}`) in your repo, list its file path in the
115
119
  `plugins` config array, and the agent merges your tools and lets your hooks
116
- observe or veto tool calls. See
120
+ observe or veto tool calls. Bare `lich`, one-shot, chat, tui, and gateway
121
+ all load `config.plugins` (`create_agent_with_plugins`). `create_agent` does
122
+ not. See
117
123
  [docs/user-guide/plugins.md](docs/user-guide/plugins.md).
118
124
 
119
125
  Skills are markdown files you write to `.lich/skills/` with `write_file`;
@@ -131,6 +137,7 @@ the next self-commit. One gated `git_commit` per run requires
131
137
  | `LICH_BASE_URL` | provider base url (ollama default: `http://localhost:11434`) |
132
138
  | `LICH_API_KEY_ENV` | env var holding the api key (unused by ollama) |
133
139
  | `LICH_ALLOW_SELF_COMMIT` | set to `1` to allow one gated `git_commit` per run; unset is fail-closed |
140
+ | `LICH_ALLOW_PRIVATE_URLS` | set to exactly `1` to let `fetch_url` / `http_request` reach private or loopback URLs; unset or any other value is fail-closed (blocked) |
134
141
  | `LICH_TEST_COMMAND` | command `run_tests` runs (default: `node node_modules/vitest/vitest.mjs run`) |
135
142
 
136
143
  ## Ollama
@@ -241,6 +248,24 @@ compression notices still start with `context compressed`.
241
248
  `welcome` substitutes `{version}`, `{model}`, and `{kind}`. `notices.compressed`
242
249
  substitutes `{chars}`; `notices.sessions` substitutes `{count}`.
243
250
 
251
+ ## Editor MCP
252
+
253
+ Two directions. lich connects **to** an editor MCP server (stdio local
254
+ command, or loopback HTTP). The game connects **to** lich through the webhook
255
+ and [`examples/game_bridge`](examples/game_bridge/README.md). Default is off.
256
+ `mcp_servers` is a closed record. Names are `mcp_<server>_<tool>`. `npx`,
257
+ `npm`, `bunx`, `uvx`, `curl`, `wget`, remote URLs, and shell metacharacters
258
+ are refused. On Bun, stdio children are not `unref`'d, so a one-shot or
259
+ other short-lived run waits for the MCP answer instead of exiting while
260
+ the child is still working; `agent.close()` (which every CLI mode calls)
261
+ kills the child.
262
+
263
+ This source has `lich mcp list|add|enable|disable|remove` (changelog 0.7.0).
264
+ From a clone: `bun src/cli.ts mcp list`. Redot is a catalog
265
+ entry (`redot --headless --mcp-server`), not a fork inside lich. Godot has
266
+ no official MCP server; lich does not download a community addon. See
267
+ [docs/user-guide/redot.md](docs/user-guide/redot.md).
268
+
244
269
  ## Development
245
270
 
246
271
  ```sh
@@ -254,15 +279,42 @@ packages in /tmp and break dependency resolution.
254
279
 
255
280
  ## Releasing
256
281
 
282
+ Update `CHANGELOG.md` first so the new version notes match what you ship
283
+ (GitHub release labels / automated notes are a follow-up).
284
+
285
+ ### GitHub Actions (preferred)
286
+
287
+ Requires the `NPM_TOKEN` repository secret (npm **automation** or
288
+ granular token with publish access to `@moikapy/lich` — not a classic
289
+ token that needs interactive OTP, which `npm publish` in CI cannot
290
+ answer). It is typically already configured; if not, add it under
291
+ **Settings → Secrets and variables → Actions → New repository secret**.
292
+ 1. Ensure Actions can push commits/tags to `main` (repo
293
+ **Settings → Actions → General → Workflow permissions**: read and
294
+ write; if branch protection blocks `GITHUB_TOKEN`, allow GitHub Actions
295
+ to bypass or push to `main`).
296
+ 2. Run: **Actions → Release → Run workflow** (from `main` only) → choose
297
+ `bump` (`patch` / `minor` / `major`, default `patch`).
298
+
299
+ The workflow runs `bun release <bump>` (typecheck, test, bump, build,
300
+ pack + audit, commit, tag, push — no force-push), then
301
+ `npm publish test/.tmp/lich-<version>.tgz --access public` with
302
+ `NODE_AUTH_TOKEN` from `NPM_TOKEN`. It refuses to publish if the pack
303
+ file is missing. Permissions include `id-token: write` for a future npm
304
+ OIDC trusted-publishing switch; today the token path is what works.
305
+
306
+ ### Local
307
+
257
308
  ```sh
258
309
  bun release patch # or minor | major
310
+ npm publish test/.tmp/lich-<version>.tgz
259
311
  ```
260
312
 
261
313
  Fails closed on a dirty tree, a non-main branch, a typecheck error, or a
262
314
  test failure; bumps via `npm version`, builds, and packs + audits
263
315
  `test/.tmp/lich-<version>.tgz` (SHA-512 + scope verification) before
264
- committing, tagging `v<version>`, and pushing main. Publishing stays manual
265
- (`npm publish test/.tmp/lich-<version>.tgz`) so npm can prompt for the OTP.
316
+ committing, tagging `v<version>`, and pushing main. Local publish stays
317
+ interactive so npm can prompt for OTP.
266
318
 
267
319
  ## License
268
320
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-7HLVKVIG.js";
3
+ } from "./chunk-WNFBIX4E.js";
4
4
 
5
5
  // src/util/theme.ts
6
6
  import { readFileSync } from "fs";
@@ -89,4 +89,4 @@ export {
89
89
  notice_flavor,
90
90
  load_theme
91
91
  };
92
- //# sourceMappingURL=chunk-JC2G3XH2.js.map
92
+ //# sourceMappingURL=chunk-CVX7LZWC.js.map
@@ -0,0 +1,58 @@
1
+ import {
2
+ catalog_by_name
3
+ } from "./chunk-WNFBIX4E.js";
4
+
5
+ // src/index.ts
6
+ import { readFileSync } from "fs";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // src/mcp/mcp_catalog_entry.ts
10
+ var PLACEHOLDER = /\$\{([a-z_]+)\}/g;
11
+ function expand(value, substitutes) {
12
+ const tokens = value.match(PLACEHOLDER) ?? [];
13
+ let next = value;
14
+ for (const token of tokens) {
15
+ const key = token.slice(2, -1);
16
+ const found = substitutes[key];
17
+ if (found === void 0 || found.length === 0) {
18
+ return void 0;
19
+ }
20
+ next = next.replace(token, found);
21
+ }
22
+ return next;
23
+ }
24
+ function catalog_client_entry(name, substitutes = {}) {
25
+ const manifest = catalog_by_name(name);
26
+ if (manifest === void 0) {
27
+ return `unknown mcp catalog entry '${name}'`;
28
+ }
29
+ if (manifest.transport !== "stdio" || manifest.command === void 0) {
30
+ return manifest.note ?? `${name} has no official mcp server to enable`;
31
+ }
32
+ const args = [];
33
+ for (const arg of manifest.args ?? []) {
34
+ const expanded = expand(arg, substitutes);
35
+ if (expanded === void 0) {
36
+ return `mcp catalog '${name}' needs a substitute for ${arg}`;
37
+ }
38
+ args.push(expanded);
39
+ }
40
+ return { enabled: false, command: manifest.command, args };
41
+ }
42
+
43
+ // src/index.ts
44
+ function read_package_version() {
45
+ const pkg_path = fileURLToPath(new URL("../package.json", import.meta.url));
46
+ const pkg = JSON.parse(readFileSync(pkg_path, "utf8"));
47
+ if (typeof pkg.version !== "string" || pkg.version.length === 0) {
48
+ throw new Error("package.json is missing version");
49
+ }
50
+ return pkg.version;
51
+ }
52
+ var LICH_VERSION = read_package_version();
53
+
54
+ export {
55
+ catalog_client_entry,
56
+ LICH_VERSION
57
+ };
58
+ //# sourceMappingURL=chunk-PZNYVGD4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/mcp/mcp_catalog_entry.ts"],"sourcesContent":["/**\n * Public surface of the lich agent harness. Pure re-exports, plus the package version.\n */\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nfunction read_package_version(): string {\n const pkg_path = fileURLToPath(new URL(\"../package.json\", import.meta.url));\n const pkg = JSON.parse(readFileSync(pkg_path, \"utf8\")) as { version?: unknown };\n if (typeof pkg.version !== \"string\" || pkg.version.length === 0) {\n throw new Error(\"package.json is missing version\");\n }\n return pkg.version;\n}\n\nexport const LICH_VERSION = read_package_version();\n\nexport { Agent, create_agent, run_agent, create_agent_with_plugins } from \"./agent/agent.js\";\nexport type { AgentRunOptions, AgentRunResult } from \"./agent/agent.js\";\nexport type { AgentConfig } from \"./agent/config.js\";\nexport { parse_agent_config } from \"./agent/config.js\";\nexport { catalog_client_entry } from \"./mcp/mcp_catalog_entry.js\";\nexport { AgentEmitter } from \"./agent/events.js\";\nexport type { AgentEvent, AgentEventHandler, AgentEvents } from \"./agent/events.js\";\nexport type { LoopOutcome, LoopParams } from \"./agent/loop.js\";\nexport type {\n ChatOptions,\n ChatResult,\n Message,\n ProviderConfig,\n ToolCall,\n ToolDefinition,\n Usage,\n} from \"./providers/types.js\";\nexport { ProviderError } from \"./providers/types.js\";\nexport { ToolExecutor } from \"./tools/executor.js\";\nexport { ToolRegistry } from \"./tools/registry.js\";\nexport type { Tool, ToolContext, ToolResult } from \"./tools/types.js\";\nexport { register_builtin_tools } from \"./tools/builtin/index.js\";\nexport { HookedToolRunner } from \"./plugins/hooks.js\";\nexport { load_plugins, plugin_errors_summary } from \"./plugins/loader.js\";\nexport type { LoadedPlugin, PluginLoadError } from \"./plugins/loader.js\";\nexport type {\n AfterToolCallInfo,\n BeforeToolCallInfo,\n BeforeToolCallResult,\n HookContext,\n Plugin,\n PluginHooks,\n RunEndInfo,\n} from \"./plugins/types.js\";","/**\n * Install shape: turn a catalog manifest into a disabled mcp_servers entry.\n * Does not spawn, download, or copy secrets.\n */\nimport { catalog_by_name } from \"./mcp_catalog.js\";\n\nconst PLACEHOLDER = /\\$\\{([a-z_]+)\\}/g;\n\nfunction expand(value: string, substitutes: Record<string, string>): string | undefined {\n const tokens = value.match(PLACEHOLDER) ?? [];\n let next = value;\n for (const token of tokens) {\n const key = token.slice(2, -1);\n const found = substitutes[key];\n if (found === undefined || found.length === 0) {\n return undefined;\n }\n next = next.replace(token, found);\n }\n return next;\n}\n\n/** Write the client entry. The user sets enabled. Godot has nothing to write. */\nexport function catalog_client_entry(\n name: string,\n substitutes: Record<string, string> = {},\n): Record<string, unknown> | string {\n const manifest = catalog_by_name(name);\n if (manifest === undefined) {\n return `unknown mcp catalog entry '${name}'`;\n }\n if (manifest.transport !== \"stdio\" || manifest.command === undefined) {\n return manifest.note ?? `${name} has no official mcp server to enable`;\n }\n const args: string[] = [];\n for (const arg of manifest.args ?? []) {\n const expanded = expand(arg, substitutes);\n if (expanded === undefined) {\n return `mcp catalog '${name}' needs a substitute for ${arg}`;\n }\n args.push(expanded);\n }\n return { enabled: false, command: manifest.command, args };\n}\n"],"mappings":";;;;;AAGA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;;;ACE9B,IAAM,cAAc;AAEpB,SAAS,OAAO,OAAe,aAAyD;AACtF,QAAM,SAAS,MAAM,MAAM,WAAW,KAAK,CAAC;AAC5C,MAAI,OAAO;AACX,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,MAAM,MAAM,GAAG,EAAE;AAC7B,UAAM,QAAQ,YAAY,GAAG;AAC7B,QAAI,UAAU,UAAa,MAAM,WAAW,GAAG;AAC7C,aAAO;AAAA,IACT;AACA,WAAO,KAAK,QAAQ,OAAO,KAAK;AAAA,EAClC;AACA,SAAO;AACT;AAGO,SAAS,qBACd,MACA,cAAsC,CAAC,GACL;AAClC,QAAM,WAAW,gBAAgB,IAAI;AACrC,MAAI,aAAa,QAAW;AAC1B,WAAO,8BAA8B,IAAI;AAAA,EAC3C;AACA,MAAI,SAAS,cAAc,WAAW,SAAS,YAAY,QAAW;AACpE,WAAO,SAAS,QAAQ,GAAG,IAAI;AAAA,EACjC;AACA,QAAM,OAAiB,CAAC;AACxB,aAAW,OAAO,SAAS,QAAQ,CAAC,GAAG;AACrC,UAAM,WAAW,OAAO,KAAK,WAAW;AACxC,QAAI,aAAa,QAAW;AAC1B,aAAO,gBAAgB,IAAI,4BAA4B,GAAG;AAAA,IAC5D;AACA,SAAK,KAAK,QAAQ;AAAA,EACpB;AACA,SAAO,EAAE,SAAS,OAAO,SAAS,SAAS,SAAS,KAAK;AAC3D;;;ADrCA,SAAS,uBAA+B;AACtC,QAAM,WAAW,cAAc,IAAI,IAAI,mBAAmB,YAAY,GAAG,CAAC;AAC1E,QAAM,MAAM,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC;AACrD,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW,GAAG;AAC/D,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,SAAO,IAAI;AACb;AAEO,IAAM,eAAe,qBAAqB;","names":[]}