opencode-skill-autodiscovery 1.1.4 → 1.3.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/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # opencode-skill-autodiscovery
2
2
 
3
3
  An [opencode](https://opencode.ai) plugin that auto-discovers skills installed by
4
- VS Code agent plugins and Claude Code plugins on the current machine, and
5
- registers them with opencode's `skills.paths` so they appear in every session.
6
- Each discovered skill is also exposed as a `/skill-name` slash command that
7
- loads the skill and routes the rest of your message through it.
4
+ VS Code agent plugins, Claude Code plugins, and [Agent Plugins
5
+ 1.0.0](https://agent-plugins.org) conformant packages on the current machine,
6
+ and registers them with opencode's `skills.paths` so they appear in every
7
+ session. Each discovered skill is also exposed as a `/skill-name` slash command
8
+ that loads the skill and routes the rest of your message through it.
8
9
 
9
10
  ## Why
10
11
 
@@ -26,10 +27,63 @@ setup:
26
27
  - Claude Code plugins: `~/.claude/plugins/installed_plugins.json`
27
28
  - Claude Code plugins on a remote host (SSH/remote sessions):
28
29
  `~/.claude/remote/plugins/installed_plugins.json`
30
+ - **Agent Plugins 1.0.0 packages** distributed via npm. opencode installs npm
31
+ plugins into its own cache (`~/.cache/opencode/packages/...`), not the
32
+ project's `node_modules`, and a `skills.paths` entry relative to the project
33
+ dir silently resolves to nothing. This plugin scans both the opencode plugin
34
+ cache and the project's `node_modules` for packages carrying a root
35
+ `plugin.json` whose `$schema` is `https://agent-plugins.org/schemas/...`,
36
+ and registers their `skills/` with **absolute** paths — so an npm-distributed
37
+ Agent Plugins package (e.g. `@dodopayments/opencode-plugin`) just works with
38
+ `"plugin": ["opencode-skill-autodiscovery"]` and nothing else.
29
39
 
30
40
  Each points at plugin directories that contain `SKILL.md` files. This plugin
31
41
  reads the manifests (including the remote `cache.json` LRU), resolves each
32
42
  entry to its on-disk skill directories, and registers them with opencode.
43
+ When a discovered package carries a conformant root `plugin.json`, that manifest
44
+ is preferred (its `skills/` children are registered as-is); otherwise the plugin
45
+ falls back to a tree walk so legacy layouts keep working.
46
+
47
+ ### MCP servers (opt-in)
48
+
49
+ With the `mcp` option, the plugin also reads each discovered package's `mcp.json`
50
+ and maps it onto opencode's `config.mcp`:
51
+
52
+ | Agent Plugins server | opencode entry |
53
+ |---|---|
54
+ | `{ "type": "stdio", "command", "args", "env" }` | `{ "type": "local", "command": [...], "environment": {...} }` |
55
+ | `{ "type": "streamable-http", "url" }` | `{ "type": "remote", "url" }` |
56
+ | `{ "type": "sse" }` | skipped (opencode has no SSE transport) |
57
+
58
+ `${PLUGIN_ROOT}` and `${PLUGIN_DATA}` placeholders are expanded in `args`/`env`,
59
+ and both variables are injected into each stdio server's environment
60
+ (`PLUGIN_DATA` points at
61
+ `{opencode state}/plugin-data/{packageName}`). Invalid entries are skipped
62
+ per-entry, never fatally. `sse` servers and stdio `cwd` (which opencode cannot
63
+ represent) are dropped with a log line.
64
+
65
+ ### Agents (opt-in)
66
+
67
+ Agent Plugins 1.0.0 has no portable "agents" component type (only skills and
68
+ MCP servers), so agents are contributed through the spec's client-extension
69
+ mechanism. With the `agents` option, the plugin reads agents from three
70
+ sources, in order:
71
+
72
+ 1. `plugin.json` → `extensions["dev.opencode"].agents` (a map of agent name →
73
+ opencode `agent` config).
74
+ 2. A `dev.opencode/agents/<name>.json` extension directory (one opencode agent
75
+ config per file).
76
+ 3. A legacy Claude Code plugin shim: `.claude-plugin/plugin.json` `agents`,
77
+ mapping `description` and `systemPrompt` (or the `agents/<name>/AGENTS.md`
78
+ body) onto an opencode agent.
79
+
80
+ Discovered agents are registered as `config.agent.<name>` with the same rules
81
+ as commands: user-defined agents are never overwritten, same-source mirrors are
82
+ collapsed, and cross-source collisions become `<package>-<agent>`.
83
+
84
+ **Trust note:** a package-supplied `permission` block is always dropped — agent
85
+ permissions are too powerful to inherit from a package by default. If you need
86
+ one, define the agent yourself in `opencode.json` (which always wins).
33
87
 
34
88
  ### Slash commands
35
89
 
@@ -45,7 +99,8 @@ Context: $ARGUMENTS
45
99
 
46
100
  So `/spec plan the migration` loads the `spec` skill and runs it against
47
101
  `plan the migration`. The command's description is taken from the skill's
48
- frontmatter; existing commands with the same name are left untouched.
102
+ frontmatter; existing commands with the same name are never overwritten (a
103
+ colliding skill from a different source is registered as `/package-skill`).
49
104
 
50
105
  ## Install
51
106
 
@@ -57,20 +112,33 @@ Add the package name to the `plugin` array in your `opencode.json`:
57
112
  }
58
113
  ```
59
114
 
60
- Use the tuple form to add extra root directories to scan (e.g. a non-standard
61
- VS Code data location on a remote host):
115
+ Use the tuple form to configure options:
62
116
 
63
117
  ```json
64
118
  {
65
119
  "plugin": [
66
120
  [
67
121
  "opencode-skill-autodiscovery",
68
- { "extraRoots": ["/home/user/.vscode-server"] }
122
+ {
123
+ "extraRoots": ["/home/user/.vscode-server"],
124
+ "scanCache": true,
125
+ "scanNodeModules": true,
126
+ "mcp": false,
127
+ "agents": false
128
+ }
69
129
  ]
70
130
  ]
71
131
  }
72
132
  ```
73
133
 
134
+ | Option | Default | Meaning |
135
+ |---|---|---|
136
+ | `extraRoots` | `[]` | Extra root directories to scan (e.g. a non-standard VS Code data location on a remote host). |
137
+ | `scanCache` | `true` | Scan opencode's plugin cache (`~/.cache/opencode/packages/*`) for Agent Plugins packages. |
138
+ | `scanNodeModules` | `true` | Scan the project's `node_modules` (incl. `@scope/*`) for Agent Plugins packages. |
139
+ | `mcp` | `false` | Also register MCP servers from discovered packages' `mcp.json`. |
140
+ | `agents` | `false` | Also register agents from packages (see "Agents" above). |
141
+
74
142
  ## Notes
75
143
 
76
144
  - Discovery is inherently **machine-local**: it reads manifests from the home
@@ -89,14 +157,23 @@ VS Code data location on a remote host):
89
157
  cloned-but-uninstalled marketplaces on setups that do have a manifest.
90
158
  - VS Code account sync only syncs your marketplace extension list; each machine
91
159
  still has its own `installed.json`/`cache.json` that this plugin reads.
92
- - The plugin is a no-op when no VS Code or Claude plugin manifests exist, or
93
- when they contain no skills.
160
+ - A package is only treated as an Agent Plugins package when its root
161
+ `plugin.json` declares a `$schema` under `https://agent-plugins.org/schemas/`.
162
+ Everything else is ignored by the cache/node_modules scanners and falls back
163
+ to the tree walk elsewhere.
164
+ - The same plugin can be materialised in several VS Code layouts at once
165
+ (local clone + synced bundle + marketplace clone). `skills.paths` keeps all
166
+ paths; slash commands and MCP servers are de-duplicated so mirrors don't
167
+ create a wall of `/mirror-of-...` junk.
168
+ - The plugin is a no-op when no manifests or conformant packages exist, or when
169
+ they contain no skills.
94
170
 
95
171
  ## Development
96
172
 
97
173
  ```sh
98
174
  npm install
99
175
  npm run build # tsc -> dist/
176
+ npm test # build + node --test (fixture-based unit tests)
100
177
  ```
101
178
 
102
179
  Publish:
@@ -0,0 +1,18 @@
1
+ import type { PluginPackage } from "./discovery.js";
2
+ export type AgentConfig = {
3
+ model?: string;
4
+ temperature?: number;
5
+ top_p?: number;
6
+ prompt?: string;
7
+ tools?: Record<string, boolean>;
8
+ disable?: boolean;
9
+ description?: string;
10
+ mode?: "subagent" | "primary" | "all";
11
+ color?: string;
12
+ maxSteps?: number;
13
+ };
14
+ export declare function readAgents(pkg: PluginPackage): Array<{
15
+ name: string;
16
+ agent: AgentConfig;
17
+ }>;
18
+ //# sourceMappingURL=agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AA4EF,wBAAgB,UAAU,CACxB,GAAG,EAAE,aAAa,GACjB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC,CA0D7C"}
package/dist/agents.js ADDED
@@ -0,0 +1,143 @@
1
+ import { readFileSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { log } from "./log.js";
4
+ // Reverse-DNS namespace this plugin (and opencode, by convention) owns for
5
+ // client-specific manifest data and extension directories (Agent Plugins 5.6/8).
6
+ const OPENCODE_NS = "dev.opencode";
7
+ const MODES = new Set(["subagent", "primary", "all"]);
8
+ function asRecord(value) {
9
+ return typeof value === "object" && value !== null
10
+ ? value
11
+ : null;
12
+ }
13
+ function readJson(path) {
14
+ try {
15
+ return JSON.parse(readFileSync(path, "utf8"));
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ // Converts a raw, package-supplied agent object into an opencode AgentConfig.
22
+ // `permission` blocks are dropped (too powerful to inherit by default) and
23
+ // unknown/mistyped keys are ignored. Returns null when nothing usable is left.
24
+ function toAgentConfig(raw) {
25
+ const src = asRecord(raw);
26
+ if (!src)
27
+ return null;
28
+ const agent = {};
29
+ const stringValue = (key) => typeof src[key] === "string" ? src[key] : undefined;
30
+ const numberValue = (key) => typeof src[key] === "number" && Number.isFinite(src[key])
31
+ ? src[key]
32
+ : undefined;
33
+ const model = stringValue("model");
34
+ const prompt = stringValue("prompt");
35
+ const description = stringValue("description");
36
+ const color = stringValue("color");
37
+ const temperature = numberValue("temperature");
38
+ const topP = numberValue("top_p");
39
+ const maxSteps = numberValue("maxSteps");
40
+ if (model)
41
+ agent.model = model;
42
+ if (prompt)
43
+ agent.prompt = prompt;
44
+ if (description)
45
+ agent.description = description;
46
+ if (color)
47
+ agent.color = color;
48
+ if (temperature !== undefined)
49
+ agent.temperature = temperature;
50
+ if (topP !== undefined)
51
+ agent.top_p = topP;
52
+ if (maxSteps !== undefined)
53
+ agent.maxSteps = maxSteps;
54
+ if (typeof src.disable === "boolean")
55
+ agent.disable = src.disable;
56
+ if (typeof src.mode === "string" && MODES.has(src.mode)) {
57
+ agent.mode = src.mode;
58
+ }
59
+ const tools = asRecord(src.tools);
60
+ if (tools) {
61
+ const filtered = {};
62
+ for (const [name, value] of Object.entries(tools)) {
63
+ if (typeof value === "boolean")
64
+ filtered[name] = value;
65
+ }
66
+ agent.tools = filtered;
67
+ }
68
+ if (src.permission !== undefined) {
69
+ log("dropping permission block from a package-supplied agent: too powerful to inherit");
70
+ }
71
+ if (!agent.description && !agent.prompt)
72
+ return null;
73
+ return agent;
74
+ }
75
+ // Discovers agents contributed by a package, in order:
76
+ // 1. plugin.json `extensions["dev.opencode"].agents` (Agent Plugins 5.6)
77
+ // 2. a `dev.opencode/agents/<name>.json` extension directory (Agent Plugins 8.2)
78
+ // 3. a legacy Claude Code plugin shim: `.claude-plugin/plugin.json` `agents`
79
+ // plus `agents/<name>/AGENTS.md` when no systemPrompt is declared.
80
+ // Returns a stable, de-duplicated list keyed by agent name.
81
+ export function readAgents(pkg) {
82
+ const out = new Map();
83
+ const manifest = asRecord(readJson(join(pkg.root, "plugin.json")));
84
+ const extensions = asRecord(manifest?.extensions);
85
+ const opencodeExt = asRecord(extensions?.[OPENCODE_NS]);
86
+ const manifestAgents = asRecord(opencodeExt?.agents);
87
+ if (manifestAgents) {
88
+ for (const [name, raw] of Object.entries(manifestAgents)) {
89
+ if (out.has(name))
90
+ continue;
91
+ const agent = toAgentConfig(raw);
92
+ if (agent)
93
+ out.set(name, agent);
94
+ }
95
+ }
96
+ const extDir = join(pkg.root, OPENCODE_NS, "agents");
97
+ let extEntries = [];
98
+ try {
99
+ extEntries = readdirSync(extDir);
100
+ }
101
+ catch {
102
+ extEntries = [];
103
+ }
104
+ for (const entry of extEntries) {
105
+ if (!entry.endsWith(".json"))
106
+ continue;
107
+ const name = entry.slice(0, -".json".length);
108
+ if (out.has(name))
109
+ continue;
110
+ const agent = toAgentConfig(readJson(join(extDir, entry)));
111
+ if (agent)
112
+ out.set(name, agent);
113
+ }
114
+ const claudeManifest = asRecord(readJson(join(pkg.root, ".claude-plugin", "plugin.json")));
115
+ const claudeAgents = asRecord(claudeManifest?.agents);
116
+ if (claudeAgents) {
117
+ for (const [name, raw] of Object.entries(claudeAgents)) {
118
+ if (out.has(name))
119
+ continue;
120
+ const src = asRecord(raw);
121
+ if (!src || typeof src.description !== "string")
122
+ continue;
123
+ const agent = { description: src.description };
124
+ if (typeof src.systemPrompt === "string" && src.systemPrompt) {
125
+ agent.prompt = src.systemPrompt;
126
+ }
127
+ else {
128
+ try {
129
+ agent.prompt = readFileSync(join(pkg.root, "agents", name, "AGENTS.md"), "utf8");
130
+ }
131
+ catch {
132
+ // No prompt file; the description alone is enough to register.
133
+ }
134
+ }
135
+ if (typeof src.model === "string")
136
+ agent.model = src.model;
137
+ if (agent.prompt || agent.description)
138
+ out.set(name, agent);
139
+ }
140
+ }
141
+ return [...out.entries()].map(([name, agent]) => ({ name, agent }));
142
+ }
143
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { AgentConfig } from "./agents.js";
2
+ import type { McpEntry } from "./mcp.js";
3
+ export { readAgents } from "./agents.js";
4
+ export type { AgentConfig } from "./agents.js";
5
+ export { readMcp } from "./mcp.js";
6
+ export type { McpEntry } from "./mcp.js";
7
+ export type PackageSource = "claude" | "vscode" | "opencode-cache" | "node_modules" | "extra";
8
+ export type PluginPackage = {
9
+ source: PackageSource;
10
+ name: string;
11
+ root: string;
12
+ skillDirs: string[];
13
+ mcpPath?: string;
14
+ /** Agent Plugins version declared by plugin.json, e.g. "1.0.0". */
15
+ schemaVersion?: string;
16
+ };
17
+ export type SkillInfo = {
18
+ dir: string;
19
+ name: string;
20
+ description: string;
21
+ };
22
+ export type ConfigPatch = {
23
+ skillPaths: string[];
24
+ commands: Array<{
25
+ name: string;
26
+ description: string;
27
+ template: string;
28
+ }>;
29
+ mcp: Array<{
30
+ key: string;
31
+ entry: McpEntry;
32
+ }>;
33
+ agents: Array<{
34
+ name: string;
35
+ agent: AgentConfig;
36
+ }>;
37
+ };
38
+ export type ConfigLike = {
39
+ skills?: {
40
+ paths?: string[];
41
+ };
42
+ command?: Record<string, {
43
+ description?: string;
44
+ template: string;
45
+ }>;
46
+ mcp?: Record<string, McpEntry>;
47
+ agent?: Record<string, AgentConfig | undefined>;
48
+ };
49
+ export declare function contains(parent: string, child: string): boolean;
50
+ export declare function readSkillInfo(dir: string): SkillInfo | null;
51
+ export declare function readPackage(root: string, source: PackageSource): PluginPackage | null;
52
+ export declare function findSkillDirs(root: string, out: Set<string>, seen: Set<string>): void;
53
+ export declare function packageFromDir(root: string, source: PackageSource): PluginPackage | null;
54
+ export declare function collectVscodeManifest(out: PluginPackage[], installedJson: string): void;
55
+ export declare function collectVscodeCache(out: PluginPackage[], cacheJson: string): void;
56
+ export declare function collectVscode(out: PluginPackage[], extra: string[]): void;
57
+ export declare function collectClaudeManifest(out: PluginPackage[], installedJson: string): void;
58
+ export declare function collectClaude(out: PluginPackage[]): void;
59
+ export declare function opencodeCacheRoot(): string;
60
+ export declare function collectOpencodeCache(packagesRoot: string, out: PluginPackage[]): void;
61
+ export declare function collectNodeModules(nodeModulesRoot: string, out: PluginPackage[]): void;
62
+ export declare function planConfig(packages: PluginPackage[], taken?: {
63
+ commands?: Iterable<string>;
64
+ mcp?: Iterable<string>;
65
+ agents?: Iterable<string>;
66
+ }): ConfigPatch;
67
+ export declare function applyConfigPatch(config: ConfigLike, plan: ConfigPatch, enabled: {
68
+ mcp: boolean;
69
+ agents: boolean;
70
+ }): void;
71
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,QAAQ,GACR,gBAAgB,GAChB,cAAc,GACd,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,GAAG,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;IAC7C,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,CAAC;CACjD,CAAC;AAmBF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAM/D;AAID,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAkB3D;AAMD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,GACpB,aAAa,GAAG,IAAI,CA0DtB;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAoB9E;AAuBD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,GACpB,aAAa,GAAG,IAAI,CAYtB;AA2DD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,EAAE,EACpB,aAAa,EAAE,MAAM,GACpB,IAAI,CAgBN;AASD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA6BhF;AA4BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAIzE;AAID,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,EAAE,EACpB,aAAa,EAAE,MAAM,GACpB,IAAI,CAgBN;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,IAAI,CAmBxD;AAID,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAMD,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAAE,GACnB,IAAI,CAYN;AAKD,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,aAAa,EAAE,GACnB,IAAI,CA6BN;AA2BD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,GAAE;IACL,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACtB,GACL,WAAW,CA4Gb;AAMD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACzC,IAAI,CAyCN"}