@frontmcp/plugin-remember 1.9.6 → 1.9.7
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 +152 -45
- package/esm/package.json +11 -7
- package/package.json +11 -7
- package/remember.context-extension.d.ts +3 -6
- package/remember.context-extension.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -1,71 +1,178 @@
|
|
|
1
1
|
# @frontmcp/plugin-remember
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Gives the tools of a [FrontMCP](https://frontmcp.dev) server a small encrypted key-value memory, `this.remember`, so a
|
|
4
|
+
tool can store something on one call and read it on a later one: a user's language, a draft, the last record they
|
|
5
|
+
opened. Values are encrypted before they're stored, in memory, Redis or Vercel KV. Each value lives in a scope
|
|
6
|
+
(`session`, `user`, `tool` or `global`) that decides who can read it back. Turn on `tools.enabled` and the plugin also
|
|
7
|
+
gives the model four tools to remember things itself.
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/@frontmcp/plugin-remember) [](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
14
|
npm install @frontmcp/plugin-remember
|
|
9
15
|
```
|
|
10
16
|
|
|
17
|
+
The plugin runs inside a FrontMCP server, so your app needs `@frontmcp/sdk`, at the same version as this package, and
|
|
18
|
+
Node.js 24 or later. Its peer dependency `@frontmcp/lazy-zod` comes with the SDK.
|
|
19
|
+
|
|
20
|
+
For the Vercel KV store (`type: 'vercel-kv'`, or `'global-store'` with a Vercel KV provider), also install the optional
|
|
21
|
+
peer `@vercel/kv`. The Redis stores use `ioredis`, which is already a dependency.
|
|
22
|
+
|
|
11
23
|
## Usage
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
Register the plugin with `RememberPlugin.init()` in the `plugins` of `@FrontMcp` (every app) or of one `@App` (that
|
|
26
|
+
app only). Importing the package also tells TypeScript about `this.remember`.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
14
29
|
import { RememberPlugin } from '@frontmcp/plugin-remember';
|
|
15
|
-
import { FrontMcp } from '@frontmcp/sdk';
|
|
30
|
+
import { App, FrontMcp, Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
31
|
+
|
|
32
|
+
@Tool({
|
|
33
|
+
name: 'set_language',
|
|
34
|
+
description: 'Set the language the user wants answers in',
|
|
35
|
+
inputSchema: { language: z.string() },
|
|
36
|
+
})
|
|
37
|
+
class SetLanguageTool extends ToolContext {
|
|
38
|
+
async execute({ language }: { language: string }) {
|
|
39
|
+
await this.remember.set('language', language, { scope: 'user' });
|
|
40
|
+
return { language };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
16
43
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
44
|
+
@Tool({ name: 'get_language', description: 'The language the user wants answers in', inputSchema: {} })
|
|
45
|
+
class GetLanguageTool extends ToolContext {
|
|
46
|
+
async execute() {
|
|
47
|
+
const language = await this.remember.get('language', { scope: 'user', defaultValue: 'en' });
|
|
48
|
+
return { language };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@App({ id: 'preferences', name: 'Preferences', tools: [SetLanguageTool, GetLanguageTool] })
|
|
53
|
+
class PreferencesApp {}
|
|
54
|
+
|
|
55
|
+
@FrontMcp({
|
|
56
|
+
info: { name: 'assistant', version: '1.0.0' },
|
|
57
|
+
apps: [PreferencesApp],
|
|
58
|
+
plugins: [RememberPlugin.init({ type: 'memory' })],
|
|
59
|
+
})
|
|
60
|
+
export default class Server {}
|
|
20
61
|
```
|
|
21
62
|
|
|
22
|
-
|
|
63
|
+
`user` scope needs a signed-in caller. An anonymous caller is refused with `RememberIdentityError`; see
|
|
64
|
+
[Scopes](#scopes).
|
|
65
|
+
|
|
66
|
+
## Options
|
|
67
|
+
|
|
68
|
+
Every option is optional. `RememberPlugin.init()` and `plugins: [RememberPlugin]` both keep values in memory.
|
|
69
|
+
|
|
70
|
+
| Option | Type | Default | Description |
|
|
71
|
+
| ---------------------- | ------------------------------------------------------------------------ | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `type` | `'memory' \| 'redis' \| 'redis-client' \| 'vercel-kv' \| 'global-store'` | `'memory'` | Where values are kept. See [Stores](#stores). |
|
|
73
|
+
| `keyPrefix` | `string` | `'remember:'` | Starts every key in the store. Give each server its own when several share a Redis. |
|
|
74
|
+
| `defaultTTL` | `number` (seconds) | | How long a value set without `ttl` lives. A whole number; `0` means no default expiry. |
|
|
75
|
+
| `encryption.enabled` | `boolean` | `true` | Encrypt values before they're stored. With `false`, values are stored as plain JSON. |
|
|
76
|
+
| `encryption.customKey` | `string` | | The secret keys are derived from, in place of `REMEMBER_SECRET`. See [Encryption](#encryption). |
|
|
77
|
+
| `config` | `{ host, port, password?, db? }` | | With `type: 'redis'`: where to connect. |
|
|
78
|
+
| `client` | `Redis` (ioredis) | | With `type: 'redis-client'`: a client you created. |
|
|
79
|
+
| `url`, `token` | `string` | `KV_REST_API_URL`, `KV_REST_API_TOKEN` | With `type: 'vercel-kv'`: the store's REST URL and token. |
|
|
80
|
+
| `tools.enabled` | `boolean` | `false` | Register the [memory tools](#memory-tools). |
|
|
81
|
+
| `tools.prefix` | `string` | | Starts the memory tools' names: `'memory_'` gives `memory_recall`, and so on. |
|
|
82
|
+
| `tools.allowedScopes` | `RememberScope[]` | all four | Which scopes the memory tools accept. Another scope fails with `RememberScopeNotAllowedError`. |
|
|
83
|
+
| `skipLegacyPurge` | `boolean` | `false` | Don't delete entries written by older versions of the plugin, whose keys can no longer be read. |
|
|
84
|
+
| `legacyPurgeDelayMs` | `number` | `86400000` (24 hours) | How long after the current key layout first reached the store to wait before that purge. |
|
|
23
85
|
|
|
24
|
-
|
|
25
|
-
- **Scoped Storage**: Session, user, tool, and global scopes
|
|
26
|
-
- **Approval System**: Tool approval workflow with configurable requirements
|
|
27
|
-
- **TTL Support**: Automatic expiration of stored values
|
|
28
|
-
- **Multiple Backends**: Redis, Vercel KV, or in-memory storage
|
|
86
|
+
### Stores
|
|
29
87
|
|
|
30
|
-
|
|
88
|
+
| `type` | Where values live |
|
|
89
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| `'memory'` | A `Map` in the server's process. Lost on restart, and not shared between instances. |
|
|
91
|
+
| `'redis'` | A Redis server the plugin connects to with `config`. |
|
|
92
|
+
| `'redis-client'` | Your own `ioredis` client, in `client`. |
|
|
93
|
+
| `'vercel-kv'` | Vercel KV, through `@vercel/kv`. |
|
|
94
|
+
| `'global-store'` | The store in `@FrontMcp({ redis })`: Redis, or Vercel KV. Without `redis`, the server doesn't start. |
|
|
31
95
|
|
|
32
|
-
|
|
33
|
-
@Tool({ name: 'my_tool' })
|
|
34
|
-
class MyTool extends ToolContext {
|
|
35
|
-
async execute(input) {
|
|
36
|
-
// Store a value
|
|
37
|
-
await this.remember.set('theme', 'dark');
|
|
96
|
+
## `this.remember`
|
|
38
97
|
|
|
39
|
-
|
|
40
|
-
|
|
98
|
+
`this.remember` is available in tools, resources, prompts and agents. Every method takes a `scope` option, which
|
|
99
|
+
defaults to `'session'`.
|
|
41
100
|
|
|
42
|
-
|
|
43
|
-
|
|
101
|
+
| Method | Returns | Description |
|
|
102
|
+
| ------------------------------ | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `set(key, value, options?)` | `Promise<RememberEntry>` | Stores a JSON-serializable `value`. Options: `scope`, `ttl` (seconds), `brand`, `metadata`. |
|
|
104
|
+
| `get(key, options?)` | `Promise<T \| undefined>` | The value, or `options.defaultValue` when there is none or it expired. |
|
|
105
|
+
| `getEntry(key, options?)` | `Promise<RememberEntry \| undefined>` | The value with its `brand`, `metadata`, `createdAt`, `updatedAt` and `expiresAt`. |
|
|
106
|
+
| `update(key, value, options?)` | `Promise<boolean>` | Replaces the value, keeping its metadata, and its expiry unless you pass `ttl`. `false` when there's nothing to update. |
|
|
107
|
+
| `knows(key, options?)` | `Promise<boolean>` | Whether `get()` would find a value. |
|
|
108
|
+
| `forget(key, options?)` | `Promise<void>` | Deletes the value. |
|
|
109
|
+
| `list(options?)` | `Promise<string[]>` | The keys in a scope. `options.pattern` filters them with `*` and `?`. |
|
|
44
110
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Skip onboarding
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
```
|
|
111
|
+
`this.get(RememberAccessorToken)` returns the same accessor, and `this.tryGet(RememberAccessorToken)` returns it or
|
|
112
|
+
`undefined` where the plugin isn't installed.
|
|
52
113
|
|
|
53
|
-
##
|
|
114
|
+
## Scopes
|
|
54
115
|
|
|
55
|
-
|
|
56
|
-
|
|
116
|
+
| Scope | Who can read a value back |
|
|
117
|
+
| ------------------- | --------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `session` (default) | The same session, as the server verified it. Without a verified session, the same signed-in caller. |
|
|
119
|
+
| `user` | The same signed-in caller, across sessions. |
|
|
120
|
+
| `tool` | The same caller as `session`, and only from the tool that stored it. |
|
|
121
|
+
| `global` | Every caller. |
|
|
57
122
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
123
|
+
A scope with no caller to keep values apart throws `RememberIdentityError`: `user` scope for an anonymous caller, and
|
|
124
|
+
`session` or `tool` scope for an anonymous caller without a verified session. Under MCP 2026-07-28, which has no
|
|
125
|
+
sessions, `session` values belong to the signed-in caller and last across all their requests, so give
|
|
126
|
+
conversation-sized state a `ttl`.
|
|
127
|
+
|
|
128
|
+
## Encryption
|
|
129
|
+
|
|
130
|
+
With encryption on (the default), each value is encrypted with AES-256-GCM, with a key derived (HKDF-SHA256) from a
|
|
131
|
+
server secret and the scope's identity. The server secret is `encryption.customKey` when you set it, otherwise:
|
|
132
|
+
|
|
133
|
+
1. `REMEMBER_SECRET`, `MCP_MEMORY_SECRET` or `MCP_SESSION_SECRET` from the environment.
|
|
134
|
+
2. Outside production (`NODE_ENV` isn't `production`): a secret the plugin generates and saves to
|
|
135
|
+
`.frontmcp/remember-secret.json`. Keep `.frontmcp/` out of version control.
|
|
136
|
+
3. In production: a random secret for this process, with a warning. Values can't be read after a restart, or by
|
|
137
|
+
another instance.
|
|
138
|
+
|
|
139
|
+
Set `REMEMBER_SECRET`, or `encryption.customKey`, to the same value on every instance that shares a store.
|
|
140
|
+
|
|
141
|
+
## Memory tools
|
|
142
|
+
|
|
143
|
+
With `tools.enabled: true`, the plugin registers four tools, named with `tools.prefix` if you set one:
|
|
144
|
+
|
|
145
|
+
| Tool | Arguments |
|
|
146
|
+
| --------------- | -------------------------------------------------------- |
|
|
147
|
+
| `remember_this` | `key`, `value`, `scope?`, `ttl?`, `brand?` |
|
|
148
|
+
| `recall` | `key`, `scope?` |
|
|
149
|
+
| `forget` | `key`, `scope?` |
|
|
150
|
+
| `list_memories` | `scope?`, `pattern?`, `limit?` (default 50, at most 100) |
|
|
151
|
+
|
|
152
|
+
The package also exports their classes, `RememberThisTool`, `RecallTool`, `ForgetTool` and `ListMemoriesTool`, to list
|
|
153
|
+
in an app's `tools` yourself. Use one way or the other, not both.
|
|
154
|
+
|
|
155
|
+
## Docs
|
|
156
|
+
|
|
157
|
+
- [Remember plugin reference](https://frontmcp.dev/reference/plugins/remember): every option, scope and error.
|
|
158
|
+
- [Remembering across calls](https://frontmcp.dev/learn/remembering-across-calls): a step-by-step guide.
|
|
159
|
+
- [Redis](https://frontmcp.dev/reference/deployment/redis): the `@FrontMcp({ redis })` store that `type: 'global-store'`
|
|
160
|
+
uses.
|
|
161
|
+
|
|
162
|
+
## Related packages
|
|
163
|
+
|
|
164
|
+
- [`@frontmcp/sdk`](https://www.npmjs.com/package/@frontmcp/sdk): the FrontMCP framework this plugin runs in.
|
|
165
|
+
- [`@frontmcp/plugin-approval`](https://www.npmjs.com/package/@frontmcp/plugin-approval): refuses a tool until an
|
|
166
|
+
approval is recorded for the caller. Tool approval lives there, not in this plugin.
|
|
167
|
+
- [`@frontmcp/plugin-cache`](https://www.npmjs.com/package/@frontmcp/plugin-cache): caches tool results.
|
|
168
|
+
- [`@frontmcp/plugins`](https://www.npmjs.com/package/@frontmcp/plugins): re-exports this plugin with other official
|
|
169
|
+
plugins.
|
|
170
|
+
|
|
171
|
+
## Contributing
|
|
172
|
+
|
|
173
|
+
Source: [`plugins/plugin-remember`](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-remember). Issues
|
|
174
|
+
and pull requests are welcome; see [CONTRIBUTING.md](https://github.com/agentfront/frontmcp/blob/main/CONTRIBUTING.md).
|
|
68
175
|
|
|
69
176
|
## License
|
|
70
177
|
|
|
71
|
-
Apache-2.0
|
|
178
|
+
Apache-2.0. See [LICENSE](https://github.com/agentfront/frontmcp/blob/main/LICENSE).
|
package/esm/package.json
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.9.
|
|
4
|
-
"description": "Remember plugin for FrontMCP
|
|
3
|
+
"version": "1.9.7",
|
|
4
|
+
"description": "Remember plugin for FrontMCP: encrypted key-value memory for tools (this.remember) in session, user, tool and global scopes, stored in memory, Redis or Vercel KV",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=24.0.0"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"frontmcp",
|
|
11
12
|
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
14
|
+
"remember",
|
|
12
15
|
"memory",
|
|
13
16
|
"session",
|
|
14
17
|
"encryption",
|
|
15
|
-
"
|
|
18
|
+
"redis",
|
|
19
|
+
"vercel-kv",
|
|
16
20
|
"plugin",
|
|
17
|
-
"frontmcp",
|
|
18
21
|
"agentfront"
|
|
19
22
|
],
|
|
20
23
|
"repository": {
|
|
@@ -49,12 +52,12 @@
|
|
|
49
52
|
}
|
|
50
53
|
},
|
|
51
54
|
"dependencies": {
|
|
52
|
-
"@frontmcp/
|
|
53
|
-
"@frontmcp/utils": "1.9.6",
|
|
55
|
+
"@frontmcp/utils": "1.9.7",
|
|
54
56
|
"ioredis": "^5.8.0"
|
|
55
57
|
},
|
|
56
58
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
59
|
+
"@frontmcp/lazy-zod": "1.9.7",
|
|
60
|
+
"@frontmcp/sdk": "1.9.7",
|
|
58
61
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
62
|
},
|
|
60
63
|
"peerDependenciesMeta": {
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
}
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
|
69
|
+
"@frontmcp/sdk": "1.9.7",
|
|
66
70
|
"reflect-metadata": "^0.2.2"
|
|
67
71
|
}
|
|
68
72
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.9.
|
|
4
|
-
"description": "Remember plugin for FrontMCP
|
|
3
|
+
"version": "1.9.7",
|
|
4
|
+
"description": "Remember plugin for FrontMCP: encrypted key-value memory for tools (this.remember) in session, user, tool and global scopes, stored in memory, Redis or Vercel KV",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=24.0.0"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"frontmcp",
|
|
11
12
|
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
14
|
+
"remember",
|
|
12
15
|
"memory",
|
|
13
16
|
"session",
|
|
14
17
|
"encryption",
|
|
15
|
-
"
|
|
18
|
+
"redis",
|
|
19
|
+
"vercel-kv",
|
|
16
20
|
"plugin",
|
|
17
|
-
"frontmcp",
|
|
18
21
|
"agentfront"
|
|
19
22
|
],
|
|
20
23
|
"repository": {
|
|
@@ -49,12 +52,12 @@
|
|
|
49
52
|
}
|
|
50
53
|
},
|
|
51
54
|
"dependencies": {
|
|
52
|
-
"@frontmcp/
|
|
53
|
-
"@frontmcp/utils": "1.9.6",
|
|
55
|
+
"@frontmcp/utils": "1.9.7",
|
|
54
56
|
"ioredis": "^5.8.0"
|
|
55
57
|
},
|
|
56
58
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
59
|
+
"@frontmcp/lazy-zod": "1.9.7",
|
|
60
|
+
"@frontmcp/sdk": "1.9.7",
|
|
58
61
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
62
|
},
|
|
60
63
|
"peerDependenciesMeta": {
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
}
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
|
69
|
+
"@frontmcp/sdk": "1.9.7",
|
|
66
70
|
"reflect-metadata": "^0.2.2"
|
|
67
71
|
}
|
|
68
72
|
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @packageDocumentation
|
|
23
23
|
*/
|
|
24
|
+
import type { ExecutionContextBase } from '@frontmcp/sdk';
|
|
24
25
|
import type { RememberAccessor } from './providers/remember-accessor.provider';
|
|
25
26
|
declare module '@frontmcp/sdk' {
|
|
26
27
|
interface ExecutionContextBase {
|
|
@@ -52,14 +53,10 @@ declare module '@frontmcp/sdk' {
|
|
|
52
53
|
*
|
|
53
54
|
* @throws Error if RememberPlugin is not installed
|
|
54
55
|
*/
|
|
55
|
-
export declare function getRemember<T extends
|
|
56
|
-
get: (token: unknown) => unknown;
|
|
57
|
-
}>(ctx: T): RememberAccessor;
|
|
56
|
+
export declare function getRemember<T extends Pick<ExecutionContextBase, 'get'>>(ctx: T): RememberAccessor;
|
|
58
57
|
/**
|
|
59
58
|
* Try to get the RememberAccessor, returning undefined if not available.
|
|
60
59
|
* Use this for graceful degradation when the plugin might not be installed.
|
|
61
60
|
*/
|
|
62
|
-
export declare function tryGetRemember<T extends
|
|
63
|
-
tryGet?: (token: unknown) => unknown;
|
|
64
|
-
}>(ctx: T): RememberAccessor | undefined;
|
|
61
|
+
export declare function tryGetRemember<T extends Partial<Pick<ExecutionContextBase, 'tryGet'>>>(ctx: T): RememberAccessor | undefined;
|
|
65
62
|
//# sourceMappingURL=remember.context-extension.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember.context-extension.d.ts","sourceRoot":"","sources":["../src/remember.context-extension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAO/E,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,oBAAoB;QAC5B;;;;;;;;;;;WAWG;QACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KACrC;IAGD,UAAU,aAAa;QACrB;;;WAGG;QACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KACrC;CACF;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS
|
|
1
|
+
{"version":3,"file":"remember.context-extension.d.ts","sourceRoot":"","sources":["../src/remember.context-extension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAO/E,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,oBAAoB;QAC5B;;;;;;;;;;;WAWG;QACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KACrC;IAGD,UAAU,aAAa;QACrB;;;WAGG;QACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KACrC;CACF;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,gBAAgB,CAEjG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC,EACpF,GAAG,EAAE,CAAC,GACL,gBAAgB,GAAG,SAAS,CAK9B"}
|