@qiqiangvae/dsh-obsidian 0.1.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/ATTRIBUTION.md +36 -0
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/cordis.patch.yml +23 -0
- package/index.js +5 -0
- package/lib/index.d.ts +64 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +351 -0
- package/lib/index.js.map +1 -0
- package/lib/lint.d.ts +25 -0
- package/lib/lint.d.ts.map +1 -0
- package/lib/lint.js +145 -0
- package/lib/lint.js.map +1 -0
- package/lib/scaffold.d.ts +26 -0
- package/lib/scaffold.d.ts.map +1 -0
- package/lib/scaffold.js +67 -0
- package/lib/scaffold.js.map +1 -0
- package/lib/search.d.ts +41 -0
- package/lib/search.d.ts.map +1 -0
- package/lib/search.js +127 -0
- package/lib/search.js.map +1 -0
- package/lib/skills.d.ts +18 -0
- package/lib/skills.d.ts.map +1 -0
- package/lib/skills.js +83 -0
- package/lib/skills.js.map +1 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +6 -0
- package/lib/types.js.map +1 -0
- package/lib/vault.d.ts +69 -0
- package/lib/vault.d.ts.map +1 -0
- package/lib/vault.js +315 -0
- package/lib/vault.js.map +1 -0
- package/package.json +66 -0
- package/skills/defuddle/SKILL.md +35 -0
- package/skills/json-canvas/SKILL.md +61 -0
- package/skills/obsidian-bases/SKILL.md +51 -0
- package/skills/obsidian-cli/SKILL.md +41 -0
- package/skills/obsidian-markdown/SKILL.md +59 -0
- package/skills/save/SKILL.md +33 -0
- package/skills/think/SKILL.md +27 -0
- package/skills/wiki/SKILL.md +45 -0
- package/skills/wiki-ingest/SKILL.md +40 -0
- package/skills/wiki-lint/SKILL.md +36 -0
- package/skills/wiki-query/SKILL.md +34 -0
package/ATTRIBUTION.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Attribution
|
|
2
|
+
|
|
3
|
+
`dsh-obsidian` is a merged adaptation of the following MIT-licensed works:
|
|
4
|
+
|
|
5
|
+
## Code adapted (with modification)
|
|
6
|
+
|
|
7
|
+
- **[Lion-1209/dsh-plugin-wiki-skills](https://github.com/Lion-1209/dsh-plugin-wiki-skills)** (MIT, © 2026 Lion-1209)
|
|
8
|
+
- Skills content adapted: `wiki`, `wiki-ingest`, `wiki-query`, `wiki-lint`, `save`, `think`
|
|
9
|
+
- Reference skills ported in: `obsidian-markdown`, `obsidian-bases`, `defuddle` (originally from kepano/obsidian-skills)
|
|
10
|
+
|
|
11
|
+
- **[Lion-1209/dsh-plugin-wiki-tools](https://github.com/Lion-1209/dsh-plugin-wiki-tools)** (MIT, © 2026 Lion-1209)
|
|
12
|
+
- Vault operation contracts (LLM Wiki pattern) followed
|
|
13
|
+
- **Re-implemented from scratch in TypeScript** for the new DSH cordis API (`ctx.tools.register`)
|
|
14
|
+
- BM25 search, type-routing, frontmatter completion, index/log bookkeeping, health check
|
|
15
|
+
|
|
16
|
+
## Reference (parity target, not directly forked)
|
|
17
|
+
|
|
18
|
+
- **[AgriciDaniel/claude-obsidian](https://github.com/AgriciDaniel/claude-obsidian)** (MIT, © 2026 AgriciDaniel)
|
|
19
|
+
- Long-term parity target. The `PORTING_PLAN.md` lists which v2.x features we will incrementally port.
|
|
20
|
+
- **No code copied** from this project.
|
|
21
|
+
|
|
22
|
+
- **[kepano/obsidian-skills](https://github.com/kepano/obsidian-skills)** (MIT)
|
|
23
|
+
- Reference for Obsidian Flavored Markdown syntax in skills.
|
|
24
|
+
|
|
25
|
+
## Changes from upstream
|
|
26
|
+
|
|
27
|
+
1. **Merged two plugins** (`dsh-plugin-wiki-skills` + `dsh-plugin-wiki-tools`) into a single `dsh-obsidian` plugin.
|
|
28
|
+
2. **Re-implemented tools layer** in modern TypeScript using the new cordis `apply(ctx)` + `ctx.tools.register` API (the old `ctx.defineTool` form was deprecated).
|
|
29
|
+
3. **Added kepano's `obsidian-cli` and `json-canvas` skills** that the Lion-1209 fork omitted.
|
|
30
|
+
4. **Removed the DSH plugin auto-update dependency** — `dsh-obsidian` is self-contained, versioned with this repo, and can be installed from this Git URL.
|
|
31
|
+
5. **Roadmap to v2.x parity** tracked in [`PORTING_PLAN.md`](./PORTING_PLAN.md).
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
- This package: MIT (see [`LICENSE`](./LICENSE))
|
|
36
|
+
- All upstream works: MIT (see [`ORIGINAL_LICENSE`](./ORIGINAL_LICENSE))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qiqiangvae
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# dsh-obsidian
|
|
2
|
+
|
|
3
|
+
Self-organizing AI second brain for Obsidian, as a single [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin.
|
|
4
|
+
|
|
5
|
+
Targets parity with [AgriciDaniel/claude-obsidian](https://github.com/AgriciDaniel/claude-obsidian) (MIT).
|
|
6
|
+
Built on the LLM Wiki pattern (Andrej Karpathy).
|
|
7
|
+
Merged fork of `dsh-plugin-wiki-skills` + `dsh-plugin-wiki-tools` — see [`ATTRIBUTION.md`](./ATTRIBUTION.md).
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
The two upstream DSH plugins were great but:
|
|
12
|
+
|
|
13
|
+
1. **DSH is in active development and breaks the public cordis API often.**
|
|
14
|
+
When that happens, the two plugins stop loading. The original maintainer
|
|
15
|
+
updates at a slower cadence than the framework.
|
|
16
|
+
2. **Splitting skills and tools is good architecture but bad UX for one person.**
|
|
17
|
+
You almost always want both.
|
|
18
|
+
|
|
19
|
+
So: one plugin, versioned together, with a clear upgrade path to v2.x features
|
|
20
|
+
(see [`PORTING_PLAN.md`](./PORTING_PLAN.md)).
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
Prerequisites:
|
|
25
|
+
|
|
26
|
+
- DSH 0.x or newer (with `dsh plugin` CLI), Node ≥ 22.19
|
|
27
|
+
- An Obsidian vault somewhere on disk
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# 1. Add the plugin
|
|
31
|
+
dsh plugin --profile web add github:qiqiangvae/dsh-obsidian
|
|
32
|
+
|
|
33
|
+
# 2. Set your vault path in your profile's cordis.patch.yml
|
|
34
|
+
# (~/.dsh/profiles/web/cordis.patch.yml)
|
|
35
|
+
#
|
|
36
|
+
# - id: dsh-obsidian
|
|
37
|
+
# config:
|
|
38
|
+
# vaultPath: /absolute/path/to/your/obsidian/vault
|
|
39
|
+
# # optional:
|
|
40
|
+
# # typeFolders: { domain: "wiki/areas" }
|
|
41
|
+
# # maxQueryResults: 10
|
|
42
|
+
#
|
|
43
|
+
# 3. Restart DSH
|
|
44
|
+
dsh web
|
|
45
|
+
|
|
46
|
+
# 4. (optional) Scaffold a fresh vault
|
|
47
|
+
# In DSH: run the wiki_scaffold tool with { template: "default", apply: true }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
To install from a local checkout (e.g. while developing this plugin):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git clone git@github.com:qiqiangvae/dsh-obsidian.git
|
|
54
|
+
cd dsh-obsidian
|
|
55
|
+
pnpm install # for dev dependencies (typescript, @types)
|
|
56
|
+
pnpm run build # compiles src/ → lib/
|
|
57
|
+
dsh plugin --profile web add link:$(pwd)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What you get
|
|
61
|
+
|
|
62
|
+
### Tools (registered on `ctx.tools`)
|
|
63
|
+
|
|
64
|
+
| Tool | What it does |
|
|
65
|
+
| ---- | ------------ |
|
|
66
|
+
| `wiki_query` | BM25 search with snippet + link graph; quick mode returns hot + index verbatim |
|
|
67
|
+
| `wiki_write` | One-page write with type-routing, frontmatter completion, index/log bookkeeping, source-hash delta skip |
|
|
68
|
+
| `wiki_lint` | Health check: duplicates, dead links, orphans, frontmatter gaps, empty sections, stale index/hot |
|
|
69
|
+
| `wiki_scaffold` | Initialize the LLM Wiki layout (dry-run by default) |
|
|
70
|
+
| `wiki_rename` | Rename a page with machinery protection |
|
|
71
|
+
| `wiki_list` | List all page titles |
|
|
72
|
+
|
|
73
|
+
### Skills (registered on `ctx.skills`)
|
|
74
|
+
|
|
75
|
+
From the Lion-1209 v1 suite:
|
|
76
|
+
|
|
77
|
+
- `wiki` — vault scaffolding and routing
|
|
78
|
+
- `wiki-ingest` — capture sources into the vault
|
|
79
|
+
- `wiki-query` — answer from the vault with citations
|
|
80
|
+
- `wiki-lint` — health-check workflow
|
|
81
|
+
- `save` — file conversation insights
|
|
82
|
+
- `think` — 10-principle reasoning loop
|
|
83
|
+
|
|
84
|
+
Plus reference skills from kepano (Obsidian Flavored Markdown, Bases) and
|
|
85
|
+
DSH-flavoured extensions:
|
|
86
|
+
|
|
87
|
+
- `obsidian-markdown`, `obsidian-bases`, `json-canvas`, `defuddle`, `obsidian-cli`
|
|
88
|
+
|
|
89
|
+
## Develop
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pnpm install
|
|
93
|
+
pnpm run build # tsc → lib/
|
|
94
|
+
pnpm test # node --test test/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Edit code under `src/`, build to `lib/`, restart DSH. To hot-reload during
|
|
98
|
+
development, also run `pnpm run dev:web` from the DSH checkout.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT. See [`LICENSE`](./LICENSE) and [`ATTRIBUTION.md`](./ATTRIBUTION.md).
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# cordis.patch.yml — DeepSeek Harness bundle patch for dsh-obsidian.
|
|
2
|
+
#
|
|
3
|
+
# When this package is installed as a bundle (the dsh.bundle.patch field in
|
|
4
|
+
# package.json points to this file), DSH applies this patch to the profile
|
|
5
|
+
# root. The `- insert:` form adds a single loader row under the id
|
|
6
|
+
# `dsh-obsidian`. The row's `name` is the npm package name, which DSH uses
|
|
7
|
+
# to resolve the entry module (this package's `main`, i.e. `./index.js`).
|
|
8
|
+
#
|
|
9
|
+
# vaultPath is REQUIRED: override this row from your profile's own
|
|
10
|
+
# cordis.patch.yml, e.g.
|
|
11
|
+
#
|
|
12
|
+
# - id: dsh-obsidian
|
|
13
|
+
# config:
|
|
14
|
+
# vaultPath: /absolute/path/to/your/obsidian/vault
|
|
15
|
+
# typeFolders: { domain: "wiki/areas" }
|
|
16
|
+
# maxQueryResults: 10
|
|
17
|
+
#
|
|
18
|
+
# If vaultPath is empty at boot, the plugin fails loud with clear
|
|
19
|
+
# instructions — never silently writes to the wrong directory.
|
|
20
|
+
|
|
21
|
+
- insert:
|
|
22
|
+
- id: dsh-obsidian
|
|
23
|
+
name: "@qiqiangvae/dsh-obsidian"
|
package/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// index.js — DSH entry point. Re-exports the compiled apply() from lib/.
|
|
2
|
+
// Keeping this file in the repo root so DSH's `main` field resolves to a
|
|
3
|
+
// conventional location; the real implementation lives in lib/index.js.
|
|
4
|
+
|
|
5
|
+
export { name, inject, apply, default } from './lib/index.js';
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index.ts — DSH plugin entry point for dsh-obsidian.
|
|
3
|
+
*
|
|
4
|
+
* Re-implementation of dsh-plugin-wiki-tools + dsh-plugin-wiki-skills, using
|
|
5
|
+
* the modern `apply(ctx, config)` signature and the `defineTool()` helper
|
|
6
|
+
* from @deepseek-ai/dsh-tools. Each tool returns structured data; the render
|
|
7
|
+
* function shapes the model-facing text.
|
|
8
|
+
*
|
|
9
|
+
* Required config (in your profile's cordis.patch.yml):
|
|
10
|
+
*
|
|
11
|
+
* - id: dsh-obsidian
|
|
12
|
+
* config:
|
|
13
|
+
* vaultPath: /absolute/path/to/your/obsidian/vault
|
|
14
|
+
*
|
|
15
|
+
* The boot fails loud if vaultPath is missing.
|
|
16
|
+
*/
|
|
17
|
+
import z from '@deepseek-ai/schemastery';
|
|
18
|
+
import type { Context } from './types.js';
|
|
19
|
+
export declare const Config: z<Schemastery.ObjectS<{
|
|
20
|
+
/** Absolute path to the Obsidian vault root. */
|
|
21
|
+
vaultPath: z<string, string>;
|
|
22
|
+
/** Max wiki_query hits in standard mode. */
|
|
23
|
+
maxQueryResults: z<number, number>;
|
|
24
|
+
/** Optional per-type folder overrides. */
|
|
25
|
+
typeFolders: z<Schemastery.ObjectS<{}>, Schemastery.ObjectT<{}>>;
|
|
26
|
+
}>, Schemastery.ObjectT<{
|
|
27
|
+
/** Absolute path to the Obsidian vault root. */
|
|
28
|
+
vaultPath: z<string, string>;
|
|
29
|
+
/** Max wiki_query hits in standard mode. */
|
|
30
|
+
maxQueryResults: z<number, number>;
|
|
31
|
+
/** Optional per-type folder overrides. */
|
|
32
|
+
typeFolders: z<Schemastery.ObjectS<{}>, Schemastery.ObjectT<{}>>;
|
|
33
|
+
}>>;
|
|
34
|
+
/** Hand-written mirror of the schema above; dsh passes this exact shape to apply. */
|
|
35
|
+
export interface ObsidianConfig {
|
|
36
|
+
vaultPath: string;
|
|
37
|
+
maxQueryResults: number;
|
|
38
|
+
typeFolders: Record<string, string>;
|
|
39
|
+
}
|
|
40
|
+
export declare const name = "dsh-obsidian";
|
|
41
|
+
export declare const inject: string[];
|
|
42
|
+
export declare function apply(ctx: Context, config: ObsidianConfig): Promise<void>;
|
|
43
|
+
declare const _default: {
|
|
44
|
+
name: string;
|
|
45
|
+
inject: string[];
|
|
46
|
+
Config: z<Schemastery.ObjectS<{
|
|
47
|
+
/** Absolute path to the Obsidian vault root. */
|
|
48
|
+
vaultPath: z<string, string>;
|
|
49
|
+
/** Max wiki_query hits in standard mode. */
|
|
50
|
+
maxQueryResults: z<number, number>;
|
|
51
|
+
/** Optional per-type folder overrides. */
|
|
52
|
+
typeFolders: z<Schemastery.ObjectS<{}>, Schemastery.ObjectT<{}>>;
|
|
53
|
+
}>, Schemastery.ObjectT<{
|
|
54
|
+
/** Absolute path to the Obsidian vault root. */
|
|
55
|
+
vaultPath: z<string, string>;
|
|
56
|
+
/** Max wiki_query hits in standard mode. */
|
|
57
|
+
maxQueryResults: z<number, number>;
|
|
58
|
+
/** Optional per-type folder overrides. */
|
|
59
|
+
typeFolders: z<Schemastery.ObjectS<{}>, Schemastery.ObjectT<{}>>;
|
|
60
|
+
}>>;
|
|
61
|
+
apply: typeof apply;
|
|
62
|
+
};
|
|
63
|
+
export default _default;
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,OAAO,CAAC,MAAM,0BAA0B,CAAC;AAQzC,OAAO,KAAK,EAAgB,OAAO,EAAkB,MAAM,YAAY,CAAC;AAQxE,eAAO,MAAM,MAAM;IACjB,gDAAgD;;IAEhD,4CAA4C;;IAE5C,0CAA0C;;;IAJ1C,gDAAgD;;IAEhD,4CAA4C;;IAE5C,0CAA0C;;GAE1C,CAAC;AAEH,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAMD,eAAO,MAAM,IAAI,iBAAiB,CAAC;AAInC,eAAO,MAAM,MAAM,UAAsB,CAAC;AAiB1C,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6N/E;;;;;QArQC,gDAAgD;;QAEhD,4CAA4C;;QAE5C,0CAA0C;;;QAJ1C,gDAAgD;;QAEhD,4CAA4C;;QAE5C,0CAA0C;;;;;AA0W5C,wBAA+C"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index.ts — DSH plugin entry point for dsh-obsidian.
|
|
3
|
+
*
|
|
4
|
+
* Re-implementation of dsh-plugin-wiki-tools + dsh-plugin-wiki-skills, using
|
|
5
|
+
* the modern `apply(ctx, config)` signature and the `defineTool()` helper
|
|
6
|
+
* from @deepseek-ai/dsh-tools. Each tool returns structured data; the render
|
|
7
|
+
* function shapes the model-facing text.
|
|
8
|
+
*
|
|
9
|
+
* Required config (in your profile's cordis.patch.yml):
|
|
10
|
+
*
|
|
11
|
+
* - id: dsh-obsidian
|
|
12
|
+
* config:
|
|
13
|
+
* vaultPath: /absolute/path/to/your/obsidian/vault
|
|
14
|
+
*
|
|
15
|
+
* The boot fails loud if vaultPath is missing.
|
|
16
|
+
*/
|
|
17
|
+
import { dirname, join } from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
21
|
+
import z from '@deepseek-ai/schemastery';
|
|
22
|
+
import { resolveLayout } from './vault.js';
|
|
23
|
+
import { search } from './search.js';
|
|
24
|
+
import { writePage, renamePage, listAllTitles } from './vault.js';
|
|
25
|
+
import { lint, writeLintReport } from './lint.js';
|
|
26
|
+
import { scaffold } from './scaffold.js';
|
|
27
|
+
import { registerAllSkills } from './skills.js';
|
|
28
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
// Config schema (validated by Schemastery at load time)
|
|
31
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
32
|
+
export const Config = z.object({
|
|
33
|
+
/** Absolute path to the Obsidian vault root. */
|
|
34
|
+
vaultPath: z.string().required(),
|
|
35
|
+
/** Max wiki_query hits in standard mode. */
|
|
36
|
+
maxQueryResults: z.number().default(10),
|
|
37
|
+
/** Optional per-type folder overrides. */
|
|
38
|
+
typeFolders: z.object({}),
|
|
39
|
+
});
|
|
40
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
// Plugin identity
|
|
42
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
export const name = 'dsh-obsidian';
|
|
44
|
+
// Inject: `tools` (the dsh-tools service that owns our wiki_query etc.) and
|
|
45
|
+
// `skills` (the dsh-skills service that bundles the SKILL.md catalog).
|
|
46
|
+
// The loader waits for these to be available before calling apply().
|
|
47
|
+
export const inject = ['tools', 'skills'];
|
|
48
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
49
|
+
// register helper — our local ToolDefinition is intentionally loose (the
|
|
50
|
+
// dsh-tools types require `execute` to return a strictly-typed `JsonValue`).
|
|
51
|
+
// At runtime, our plain objects are JSON-serializable; the cast is safe.
|
|
52
|
+
// We pass through defineTool() so dsh-tools still validates the args schema
|
|
53
|
+
// and the output schema on every call.
|
|
54
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
const reg = (ctx, def) => ctx.tools.register(defineTool(def));
|
|
57
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
58
|
+
// Apply — runs once at boot, after deps are ready
|
|
59
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
60
|
+
export async function apply(ctx, config) {
|
|
61
|
+
ctx.logger.info('dsh-obsidian activating…');
|
|
62
|
+
if (typeof config.vaultPath !== 'string' || config.vaultPath.length === 0) {
|
|
63
|
+
throw new Error('dsh-obsidian: config vaultPath is required. Set it on the dsh-obsidian row ' +
|
|
64
|
+
'in your profile cordis.patch.yml, e.g.\n' +
|
|
65
|
+
' - id: dsh-obsidian\n' +
|
|
66
|
+
' config:\n' +
|
|
67
|
+
' vaultPath: /absolute/path/to/your/obsidian/vault');
|
|
68
|
+
}
|
|
69
|
+
if (!existsSync(config.vaultPath)) {
|
|
70
|
+
ctx.logger.warn(`dsh-obsidian: vaultPath does not exist: ${config.vaultPath} ` +
|
|
71
|
+
`(create it or run wiki_scaffold to initialize)`);
|
|
72
|
+
}
|
|
73
|
+
// Materialize a PluginConfig for the helpers
|
|
74
|
+
const pluginConfig = {
|
|
75
|
+
vaultPath: config.vaultPath,
|
|
76
|
+
typeFolders: (config.typeFolders ?? {}),
|
|
77
|
+
maxQueryResults: config.maxQueryResults ?? 10,
|
|
78
|
+
};
|
|
79
|
+
const layout = resolveLayout(config.vaultPath, pluginConfig);
|
|
80
|
+
// ── tools ────────────────────────────────────────────────────────────────
|
|
81
|
+
// wiki_query
|
|
82
|
+
reg(ctx, {
|
|
83
|
+
name: 'wiki_query',
|
|
84
|
+
description: 'Search the knowledge vault. Quick mode returns the hot cache and master ' +
|
|
85
|
+
'index verbatim (read those before any page). Standard mode runs BM25 full-text ' +
|
|
86
|
+
'search over every wiki page and returns ranked matches with snippets, inbound ' +
|
|
87
|
+
'links, and outbound link counts.',
|
|
88
|
+
parameters: {
|
|
89
|
+
query: { type: 'string', required: true, description: 'search text or topic' },
|
|
90
|
+
limit: { type: 'number', description: 'max hits (default from config)' },
|
|
91
|
+
mode: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
enum: ['quick', 'standard'],
|
|
94
|
+
description: 'quick returns hot.md + index.md only; standard searches all pages',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
output: {
|
|
98
|
+
schema: { type: 'object', additionalProperties: true },
|
|
99
|
+
render: (_args, value) => [
|
|
100
|
+
{ type: 'text', text: renderQuery(value) },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
execute: async (args) => {
|
|
104
|
+
const limit = args.limit ?? pluginConfig.maxQueryResults ?? 10;
|
|
105
|
+
const mode = args.mode ?? 'standard';
|
|
106
|
+
return search(layout.wikiDir, { query: args.query, limit, mode });
|
|
107
|
+
},
|
|
108
|
+
presentCall: (args) => ({
|
|
109
|
+
card: 'generic',
|
|
110
|
+
title: `Query wiki: ${args.query}`,
|
|
111
|
+
kind: 'read',
|
|
112
|
+
rawInput: args.query,
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
// wiki_write
|
|
116
|
+
reg(ctx, {
|
|
117
|
+
name: 'wiki_write',
|
|
118
|
+
description: 'Write or update one wiki page with full bookkeeping: type-routed folder, ' +
|
|
119
|
+
'frontmatter completion (keeps `created` and unknown fields), filename-uniqueness ' +
|
|
120
|
+
'guard, master-index entry, and log entry. With source_path, records the source ' +
|
|
121
|
+
'SHA-256 and skips unchanged content unless `force`. Returns unresolvedLinks so ' +
|
|
122
|
+
'forward links during multi-page ingests are surfaced for the next pass.',
|
|
123
|
+
parameters: {
|
|
124
|
+
title: { type: 'string', required: true, description: 'page title; also filename' },
|
|
125
|
+
type: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
required: true,
|
|
128
|
+
enum: ['domain', 'area', 'project', 'resource', 'source', 'archive'],
|
|
129
|
+
description: 'page type, drives folder routing',
|
|
130
|
+
},
|
|
131
|
+
content: { type: 'string', required: true, description: 'markdown body (no frontmatter; it is added)' },
|
|
132
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'optional frontmatter tags' },
|
|
133
|
+
source_path: { type: 'string', description: 'optional path to source file; hash recorded for delta' },
|
|
134
|
+
force: { type: 'boolean', description: 'overwrite even when source hash unchanged' },
|
|
135
|
+
},
|
|
136
|
+
output: {
|
|
137
|
+
schema: { type: 'object', additionalProperties: true },
|
|
138
|
+
render: (args, value) => [
|
|
139
|
+
{ type: 'text', text: renderWrite(args, value) },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
execute: async (args) => {
|
|
143
|
+
return writePage(config.vaultPath, pluginConfig, {
|
|
144
|
+
title: args.title,
|
|
145
|
+
type: args.type,
|
|
146
|
+
content: args.content,
|
|
147
|
+
tags: args.tags,
|
|
148
|
+
source_path: args.source_path,
|
|
149
|
+
force: args.force,
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
presentCall: (args) => ({
|
|
153
|
+
card: 'generic',
|
|
154
|
+
title: `Write wiki page: ${args.title}`,
|
|
155
|
+
kind: 'other',
|
|
156
|
+
rawInput: { title: args.title, type: args.type },
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
// wiki_rename
|
|
160
|
+
reg(ctx, {
|
|
161
|
+
name: 'wiki_rename',
|
|
162
|
+
description: 'Rename a wiki page. Refuses machinery pages (Lint Report, index, hot, log) ' +
|
|
163
|
+
'and rejects non-portable filenames.',
|
|
164
|
+
parameters: {
|
|
165
|
+
old_title: { type: 'string', required: true },
|
|
166
|
+
new_title: { type: 'string', required: true },
|
|
167
|
+
},
|
|
168
|
+
output: {
|
|
169
|
+
schema: { type: 'object', additionalProperties: true },
|
|
170
|
+
render: (_args, value) => [{ type: 'text', text: renderRename(value) }],
|
|
171
|
+
},
|
|
172
|
+
execute: async (args) => {
|
|
173
|
+
return renamePage(config.vaultPath, pluginConfig, args.old_title, args.new_title);
|
|
174
|
+
},
|
|
175
|
+
presentCall: (args) => ({
|
|
176
|
+
card: 'generic',
|
|
177
|
+
title: `Rename wiki page: ${args.old_title} → ${args.new_title}`,
|
|
178
|
+
kind: 'other',
|
|
179
|
+
rawInput: { from: args.old_title, to: args.new_title },
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
// wiki_lint
|
|
183
|
+
reg(ctx, {
|
|
184
|
+
name: 'wiki_lint',
|
|
185
|
+
description: 'Health-check the knowledge vault: duplicate filenames, dead wikilinks, orphan ' +
|
|
186
|
+
'pages, frontmatter gaps, empty sections, stale index entries, stale hot cache. ' +
|
|
187
|
+
'Report only — every issue carries a suggestion. Writes the dated report to ' +
|
|
188
|
+
'wiki/meta/Lint Report <date>.md.',
|
|
189
|
+
parameters: {
|
|
190
|
+
fix: { type: 'boolean', description: 'placeholder for future parity; report-only in v0.1' },
|
|
191
|
+
},
|
|
192
|
+
output: {
|
|
193
|
+
schema: { type: 'object', additionalProperties: true },
|
|
194
|
+
render: (_args, value) => [{ type: 'text', text: renderLint(value) }],
|
|
195
|
+
},
|
|
196
|
+
execute: async (args) => {
|
|
197
|
+
const report = lint(config.vaultPath, pluginConfig, { fix: args.fix });
|
|
198
|
+
const reportPath = writeLintReport(config.vaultPath, pluginConfig, report);
|
|
199
|
+
return { ...report, reportPath };
|
|
200
|
+
},
|
|
201
|
+
presentCall: () => ({ card: 'generic', title: 'Lint wiki vault', kind: 'other' }),
|
|
202
|
+
});
|
|
203
|
+
// wiki_scaffold
|
|
204
|
+
reg(ctx, {
|
|
205
|
+
name: 'wiki_scaffold',
|
|
206
|
+
description: 'Scaffold a wiki vault: wiki/, .raw/, wiki/meta/, and seed files (index.md, ' +
|
|
207
|
+
'hot.md, log.md, Inbox.md). Dry-run by default — pass `apply: true` to write.',
|
|
208
|
+
parameters: {
|
|
209
|
+
template: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
enum: ['default', 'minimal', 'research'],
|
|
212
|
+
description: 'scaffold template',
|
|
213
|
+
},
|
|
214
|
+
apply: { type: 'boolean', description: 'actually write files (default false = dry run)' },
|
|
215
|
+
},
|
|
216
|
+
output: {
|
|
217
|
+
schema: { type: 'object', additionalProperties: true },
|
|
218
|
+
render: (_args, value) => [{ type: 'text', text: renderScaffold(value) }],
|
|
219
|
+
},
|
|
220
|
+
execute: async (args) => {
|
|
221
|
+
return scaffold(config.vaultPath, pluginConfig, {
|
|
222
|
+
template: args.template,
|
|
223
|
+
apply: args.apply,
|
|
224
|
+
});
|
|
225
|
+
},
|
|
226
|
+
presentCall: (args) => ({
|
|
227
|
+
card: 'generic',
|
|
228
|
+
title: `Scaffold wiki vault (${args.template ?? 'default'})`,
|
|
229
|
+
kind: 'other',
|
|
230
|
+
rawInput: { template: args.template, apply: args.apply },
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
233
|
+
// wiki_list
|
|
234
|
+
reg(ctx, {
|
|
235
|
+
name: 'wiki_list',
|
|
236
|
+
description: 'List all page titles in the vault (excluding machinery pages).',
|
|
237
|
+
parameters: {},
|
|
238
|
+
output: {
|
|
239
|
+
schema: { type: 'object', additionalProperties: true },
|
|
240
|
+
render: (_args, value) => [{ type: 'text', text: renderList(value) }],
|
|
241
|
+
},
|
|
242
|
+
execute: async () => ({ titles: [...listAllTitles(layout.wikiDir)] }),
|
|
243
|
+
presentCall: () => ({ card: 'generic', title: 'List wiki pages', kind: 'read' }),
|
|
244
|
+
});
|
|
245
|
+
// ── skills ───────────────────────────────────────────────────────────────
|
|
246
|
+
const candidates = [join(__dirname, 'skills'), join(__dirname, '..', 'skills')];
|
|
247
|
+
const skillsDir = candidates.find(p => existsSync(p));
|
|
248
|
+
if (skillsDir) {
|
|
249
|
+
const registered = registerAllSkills(ctx, skillsDir);
|
|
250
|
+
ctx.logger.info(`dsh-obsidian: registered ${registered.length} skill(s): ${registered.join(', ')}`);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
ctx.logger.warn(`dsh-obsidian: no skills/ directory found (looked in ${candidates.join(', ')})`);
|
|
254
|
+
}
|
|
255
|
+
ctx.logger.info(`dsh-obsidian ready. vault=${config.vaultPath} wiki=${layout.wikiDir}`);
|
|
256
|
+
}
|
|
257
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
258
|
+
// Render helpers — control what the model sees in tool output
|
|
259
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
260
|
+
function capText(text, max) {
|
|
261
|
+
return text.length <= max ? text : `${text.slice(0, max)}\n… (truncated at ${max} characters)`;
|
|
262
|
+
}
|
|
263
|
+
function renderQuery(value) {
|
|
264
|
+
const v = value;
|
|
265
|
+
if (!v)
|
|
266
|
+
return 'wiki_query: no result';
|
|
267
|
+
if (v.mode === 'quick') {
|
|
268
|
+
const parts = [];
|
|
269
|
+
if (typeof v.hot === 'string' && v.hot.length > 0) {
|
|
270
|
+
parts.push(`--- wiki/hot.md (recent context cache) ---\n${capText(v.hot, 6000)}`);
|
|
271
|
+
}
|
|
272
|
+
if (typeof v.index === 'string' && v.index.length > 0) {
|
|
273
|
+
parts.push(`--- wiki/index.md (master catalog) ---\n${capText(v.index, 8000)}`);
|
|
274
|
+
}
|
|
275
|
+
if (parts.length === 0)
|
|
276
|
+
return 'wiki_query (quick): the vault has no hot.md or index.md yet';
|
|
277
|
+
return `wiki_query (quick): hot cache and master index follow. Read these before any page.\n\n${parts.join('\n\n')}`;
|
|
278
|
+
}
|
|
279
|
+
if (!Array.isArray(v.results))
|
|
280
|
+
return 'wiki_query: no result';
|
|
281
|
+
const lines = [
|
|
282
|
+
`wiki_query: ${v.results.length} of ${v.totalMatches ?? v.results.length} matching pages. Open a page with the fs read tool for full content.`,
|
|
283
|
+
];
|
|
284
|
+
for (const hit of v.results) {
|
|
285
|
+
lines.push(`\n### ${hit.name}`);
|
|
286
|
+
lines.push(`path: ${hit.path} · score ${hit.score} · inbound ${hit.inbound.length}${hit.inbound.length > 0 ? ` (${hit.inbound.slice(0, 5).join(', ')})` : ''} · outbound ${hit.outbound.length}`);
|
|
287
|
+
if (hit.snippet)
|
|
288
|
+
lines.push(`> ${hit.snippet}`);
|
|
289
|
+
}
|
|
290
|
+
return capText(lines.join('\n'), 12000);
|
|
291
|
+
}
|
|
292
|
+
function renderWrite(args, value) {
|
|
293
|
+
const a = args;
|
|
294
|
+
const v = value;
|
|
295
|
+
if (!v)
|
|
296
|
+
return 'wiki_write: failed';
|
|
297
|
+
if (v.alreadyIngested === true) {
|
|
298
|
+
return `wiki_write: skipped ${a.title ?? ''} — source hash unchanged (pass force: true to re-write)`;
|
|
299
|
+
}
|
|
300
|
+
if (v.path) {
|
|
301
|
+
const action = v.created ? 'created' : 'updated';
|
|
302
|
+
const tail = Array.isArray(v.unresolvedLinks) && v.unresolvedLinks.length > 0
|
|
303
|
+
? `\nwiki_write: note — ${v.unresolvedLinks.length} unresolved wikilink(s) in this page: ${v.unresolvedLinks.slice(0, 8).join(', ')}${v.unresolvedLinks.length > 8 ? ', …' : ''}. Create those pages or fix the targets.`
|
|
304
|
+
: '';
|
|
305
|
+
return `wiki_write: ${action} ${v.path}${tail}`;
|
|
306
|
+
}
|
|
307
|
+
return `wiki_write: skipped ${a.title ?? ''}`;
|
|
308
|
+
}
|
|
309
|
+
function renderRename(value) {
|
|
310
|
+
const v = value;
|
|
311
|
+
if (!v || !v.path)
|
|
312
|
+
return 'wiki_rename: failed';
|
|
313
|
+
return `wiki_rename: [[${v.from}]] → [[${v.to}]]`;
|
|
314
|
+
}
|
|
315
|
+
function renderLint(value) {
|
|
316
|
+
const v = value;
|
|
317
|
+
if (!v || !v.totals)
|
|
318
|
+
return 'wiki_lint: failed';
|
|
319
|
+
const t = v.totals;
|
|
320
|
+
const lines = [
|
|
321
|
+
`wiki_lint: ${t.error + t.warn + t.info} issues (${t.error} error, ${t.warn} warn, ${t.info} info)`,
|
|
322
|
+
`report: ${v.reportPath ?? '(not written)'}`,
|
|
323
|
+
];
|
|
324
|
+
for (const i of (v.issues ?? []).slice(0, 60)) {
|
|
325
|
+
lines.push(`- [${i.severity}] ${i.category} · ${i.file}: ${i.message}${i.suggestion ? ' → ' + i.suggestion : ''}`);
|
|
326
|
+
}
|
|
327
|
+
if ((v.issues ?? []).length > 60)
|
|
328
|
+
lines.push(`… and ${(v.issues ?? []).length - 60} more (see the report file)`);
|
|
329
|
+
return lines.join('\n');
|
|
330
|
+
}
|
|
331
|
+
function renderScaffold(value) {
|
|
332
|
+
const v = value;
|
|
333
|
+
if (!v || !v.plan)
|
|
334
|
+
return 'wiki_scaffold: failed';
|
|
335
|
+
const p = v.plan;
|
|
336
|
+
if (v.applied) {
|
|
337
|
+
return `wiki_scaffold: created ${p.create.length} dirs, wrote ${p.write.length} files, skipped ${p.skipped.length} existing`;
|
|
338
|
+
}
|
|
339
|
+
return `wiki_scaffold (dry-run): would create ${p.create.length} dirs and write ${p.write.length} files. Pass apply: true to actually write.`;
|
|
340
|
+
}
|
|
341
|
+
function renderList(value) {
|
|
342
|
+
const v = value;
|
|
343
|
+
if (!v || !Array.isArray(v.titles))
|
|
344
|
+
return 'wiki_list: failed';
|
|
345
|
+
if (v.titles.length === 0)
|
|
346
|
+
return 'wiki_list: vault is empty';
|
|
347
|
+
return `wiki_list: ${v.titles.length} pages\n\n` + v.titles.map(t => `- [[${t}]]`).join('\n');
|
|
348
|
+
}
|
|
349
|
+
// default export for tooling that expects the module form
|
|
350
|
+
export default { name, inject, Config, apply };
|
|
351
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,CAAC,MAAM,0BAA0B,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,iFAAiF;AACjF,wDAAwD;AACxD,iFAAiF;AAEjF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,gDAAgD;IAChD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,4CAA4C;IAC5C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACvC,0CAA0C;IAC1C,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;CAC1B,CAAC,CAAC;AASH,iFAAiF;AACjF,kBAAkB;AAClB,iFAAiF;AAEjF,MAAM,CAAC,MAAM,IAAI,GAAG,cAAc,CAAC;AACnC,4EAA4E;AAC5E,uEAAuE;AACvE,qEAAqE;AACrE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAE1C,iFAAiF;AACjF,yEAAyE;AACzE,6EAA6E;AAC7E,yEAAyE;AACzE,4EAA4E;AAC5E,uCAAuC;AACvC,iFAAiF;AAEjF,8DAA8D;AAC9D,MAAM,GAAG,GAAG,CAAC,GAAY,EAAE,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAE5E,iFAAiF;AACjF,kDAAkD;AAClD,iFAAiF;AAEjF,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAY,EAAE,MAAsB;IAC9D,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAE5C,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,0CAA0C;YAC1C,wBAAwB;YACxB,eAAe;YACf,wDAAwD,CAC3D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,2CAA2C,MAAM,CAAC,SAAS,GAAG;YAC5D,gDAAgD,CACnD,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,MAAM,YAAY,GAAiB;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAA2B;QACjE,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,EAAE;KAC9C,CAAC;IACF,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAE7D,4EAA4E;IAE5E,aAAa;IACb,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,0EAA0E;YAC1E,iFAAiF;YACjF,gFAAgF;YAChF,kCAAkC;QACpC,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,sBAAsB,EAAE;YAC9E,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;YACxE,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;gBAC3B,WAAW,EAAE,mEAAmE;aACjF;SACF;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE,CAAC;gBAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;aAC3C;SACF;QACD,OAAO,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YAC3B,MAAM,KAAK,GAAI,IAAI,CAAC,KAA4B,IAAI,YAAY,CAAC,eAAe,IAAI,EAAE,CAAC;YACvF,MAAM,IAAI,GAAI,IAAI,CAAC,IAAyC,IAAI,UAAU,CAAC;YAC3E,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAe,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,eAAe,IAAI,CAAC,KAAe,EAAE;YAC5C,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,IAAI,CAAC,KAAK;SACrB,CAAC;KACH,CAAC,CAAC;IAEH,aAAa;IACb,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,2EAA2E;YAC3E,mFAAmF;YACnF,iFAAiF;YACjF,iFAAiF;YACjF,yEAAyE;QAC3E,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2BAA2B,EAAE;YACnF,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC;gBACpE,WAAW,EAAE,kCAAkC;aAChD;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE;YACvG,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,2BAA2B,EAAE;YAC5F,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uDAAuD,EAAE;YACrG,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,2CAA2C,EAAE;SACrF;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,IAAa,EAAE,KAAc,EAAE,EAAE,CAAC;gBACzC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;aACjD;SACF;QACD,OAAO,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YAC3B,OAAO,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE;gBAC/C,KAAK,EAAE,IAAI,CAAC,KAAe;gBAC3B,IAAI,EAAE,IAAI,CAAC,IAAc;gBACzB,OAAO,EAAE,IAAI,CAAC,OAAiB;gBAC/B,IAAI,EAAE,IAAI,CAAC,IAA4B;gBACvC,WAAW,EAAE,IAAI,CAAC,WAAiC;gBACnD,KAAK,EAAE,IAAI,CAAC,KAA4B;aACzC,CAAC,CAAC;QACL,CAAC;QACD,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,oBAAoB,IAAI,CAAC,KAAe,EAAE;YACjD,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;SACjD,CAAC;KACH,CAAC,CAAC;IAEH,cAAc;IACd,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,6EAA6E;YAC7E,qCAAqC;QACvC,UAAU,EAAE;YACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC9C;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;SAC1F;QACD,OAAO,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YAC3B,OAAO,UAAU,CACf,MAAM,CAAC,SAAS,EAChB,YAAY,EACZ,IAAI,CAAC,SAAmB,EACxB,IAAI,CAAC,SAAmB,CACzB,CAAC;QACJ,CAAC;QACD,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,qBAAqB,IAAI,CAAC,SAAmB,MAAM,IAAI,CAAC,SAAmB,EAAE;YACpF,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;SACvD,CAAC;KACH,CAAC,CAAC;IAEH,YAAY;IACZ,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,gFAAgF;YAChF,iFAAiF;YACjF,6EAA6E;YAC7E,kCAAkC;QACpC,UAAU,EAAE;YACV,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,oDAAoD,EAAE;SAC5F;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;SACxF;QACD,OAAO,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAA0B,EAAE,CAAC,CAAC;YAC9F,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC;QACnC,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;KAClF,CAAC,CAAC;IAEH,gBAAgB;IAChB,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,6EAA6E;YAC7E,8EAA8E;QAChF,UAAU,EAAE;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC;gBACxC,WAAW,EAAE,mBAAmB;aACjC;YACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,gDAAgD,EAAE;SAC1F;QACD,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;SAC5F;QACD,OAAO,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;YAC3B,OAAO,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE;gBAC9C,QAAQ,EAAE,IAAI,CAAC,QAA0D;gBACzE,KAAK,EAAE,IAAI,CAAC,KAA4B;aACzC,CAAC,CAAC;QACL,CAAC;QACD,WAAW,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,wBAAyB,IAAI,CAAC,QAA+B,IAAI,SAAS,GAAG;YACpF,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;SACzD,CAAC;KACH,CAAC,CAAC;IAEH,YAAY;IACZ,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,gEAAgE;QAC7E,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACtD,MAAM,EAAE,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;SACxF;QACD,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACrE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;KACjF,CAAC,CAAC;IAEH,4EAA4E;IAE5E,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,UAAU,CAAC,MAAM,cAAc,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,uDAAuD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnG,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,MAAM,CAAC,SAAS,SAAS,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,iFAAiF;AACjF,8DAA8D;AAC9D,iFAAiF;AAEjF,SAAS,OAAO,CAAC,IAAY,EAAE,GAAW;IACxC,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,qBAAqB,GAAG,cAAc,CAAC;AACjG,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,MAAM,CAAC,GAAG,KACsN,CAAC;IACjO,IAAI,CAAC,CAAC;QAAE,OAAO,uBAAuB,CAAC;IAEvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,+CAA+C,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtD,KAAK,CAAC,IAAI,CAAC,2CAA2C,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,6DAA6D,CAAC;QAC7F,OAAO,yFAAyF,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IACvH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,uBAAuB,CAAC;IAC9D,MAAM,KAAK,GAAa;QACtB,eAAe,CAAC,CAAC,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,sEAAsE;KAC/I,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAChC,KAAK,CAAC,IAAI,CACR,SAAS,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC,KAAK,cAAc,GAAG,CAAC,OAAO,CAAC,MAAM,GACpE,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EACxE,eAAe,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CACrC,CAAC;QACF,IAAI,GAAG,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,WAAW,CAAC,IAAa,EAAE,KAAc;IAChD,MAAM,CAAC,GAAG,IAA0B,CAAC;IACrC,MAAM,CAAC,GAAG,KACwG,CAAC;IACnH,IAAI,CAAC,CAAC;QAAE,OAAO,oBAAoB,CAAC;IACpC,IAAI,CAAC,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;QAC/B,OAAO,uBAAuB,CAAC,CAAC,KAAK,IAAI,EAAE,yDAAyD,CAAC;IACvG,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACjD,MAAM,IAAI,GACR,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;YAC9D,CAAC,CAAC,wBAAwB,CAAC,CAAC,eAAe,CAAC,MAAM,yCAAyC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,0CAA0C;YACzN,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,eAAe,MAAM,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC;IAClD,CAAC;IACD,OAAO,uBAAuB,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,MAAM,CAAC,GAAG,KAAsD,CAAC;IACjE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAAE,OAAO,qBAAqB,CAAC;IAChD,OAAO,kBAAkB,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC;AACpD,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,MAAM,CAAC,GAAG,KAIT,CAAC;IACF,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,mBAAmB,CAAC;IAChD,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,MAAM,KAAK,GAAa;QACtB,cAAc,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,QAAQ;QACnG,WAAW,CAAC,CAAC,UAAU,IAAI,eAAe,EAAE;KAC7C,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrH,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE,6BAA6B,CAAC,CAAC;IACjH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,MAAM,CAAC,GAAG,KAAyG,CAAC;IACpH,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAAE,OAAO,uBAAuB,CAAC;IAClD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACjB,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,MAAM,gBAAgB,CAAC,CAAC,KAAK,CAAC,MAAM,mBAAmB,CAAC,CAAC,OAAO,CAAC,MAAM,WAAW,CAAC;IAC/H,CAAC;IACD,OAAO,yCAAyC,CAAC,CAAC,MAAM,CAAC,MAAM,mBAAmB,CAAC,CAAC,KAAK,CAAC,MAAM,6CAA6C,CAAC;AAChJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,MAAM,CAAC,GAAG,KAA8B,CAAC;IACzC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAAE,OAAO,mBAAmB,CAAC;IAC/D,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,2BAA2B,CAAC;IAC9D,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChG,CAAC;AAED,0DAA0D;AAC1D,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC"}
|