@nexrall/code-core 1.4.25 → 1.4.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agentRegistry.d.ts +45 -0
- package/dist/agent/agentRegistry.d.ts.map +1 -0
- package/dist/agent/agentRegistry.js +138 -0
- package/dist/agent/loop.d.ts +42 -0
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +305 -24
- package/dist/agent/planMode.d.ts +20 -0
- package/dist/agent/planMode.d.ts.map +1 -0
- package/dist/agent/planMode.js +252 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +409 -381
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +14 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── Plan mode ───────────────────────────────────────────────────────────────
|
|
3
|
+
//
|
|
4
|
+
// A session-wide read-only lock. The model may research as deeply as it likes
|
|
5
|
+
// and must finish by PROPOSING a plan; it cannot change anything until a human
|
|
6
|
+
// leaves plan mode. Claude Code ships the same idea, and the reason to copy it
|
|
7
|
+
// is that "read the codebase, then tell me what you'd do" is otherwise
|
|
8
|
+
// unenforceable — you are relying on the model choosing not to edit, which is a
|
|
9
|
+
// promise, not a guarantee.
|
|
10
|
+
//
|
|
11
|
+
// The design rule here is FAIL CLOSED. Everything that is not provably
|
|
12
|
+
// side-effect-free is refused. A false refusal costs the user one message
|
|
13
|
+
// ("this needs plan mode off"); a false permit silently mutates a repo the user
|
|
14
|
+
// believed was frozen. Those are not symmetric, so ambiguity always loses.
|
|
15
|
+
//
|
|
16
|
+
// Note this is a DIFFERENT axis from the sub-agent tool allowlist in
|
|
17
|
+
// agentTypes.ts. That restricts one delegated worker; this restricts the whole
|
|
18
|
+
// session including the main agent and every sub-agent it spawns.
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.PLAN_MODE_INSTRUCTIONS = void 0;
|
|
21
|
+
exports.isReadOnlyCommand = isReadOnlyCommand;
|
|
22
|
+
exports.checkPlanMode = checkPlanMode;
|
|
23
|
+
/**
|
|
24
|
+
* Tools that cannot alter anything outside the conversation.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately an ALLOWLIST. A denylist would mean every tool added later is
|
|
27
|
+
* writable-by-default in plan mode, and the person adding it has no reason to
|
|
28
|
+
* think about plan mode at all — the failure would ship silently. With an
|
|
29
|
+
* allowlist, a new tool is refused until someone deliberately classifies it,
|
|
30
|
+
* and the refusal is visible the first time anybody tries it.
|
|
31
|
+
*/
|
|
32
|
+
const READ_ONLY_TOOLS = new Set([
|
|
33
|
+
'read_file', 'search_files', 'glob', 'list_directory', 'notebook_read',
|
|
34
|
+
// Planning bookkeeping. todo_write persists only to the session's own todo
|
|
35
|
+
// list, not the repo, so it stays available — a plan mode that cannot draft
|
|
36
|
+
// a checklist is missing the point of plan mode.
|
|
37
|
+
'todo_write', 'todo_read',
|
|
38
|
+
// Reading memory is fine; memory_write is NOT here on purpose. Memory is
|
|
39
|
+
// durable state that survives the session, so writing it is a real mutation
|
|
40
|
+
// even though no file in the repo changes.
|
|
41
|
+
'memory_read',
|
|
42
|
+
'use_skill',
|
|
43
|
+
'fetch_url', 'web_search',
|
|
44
|
+
// Delegating research is ALLOWED, and this is safe rather than a hole:
|
|
45
|
+
// runSubTask passes planMode down, so the sub-agent is under the same lock and
|
|
46
|
+
// its own write tools are refused by this very function one level deeper.
|
|
47
|
+
//
|
|
48
|
+
// Worth allowing rather than blanket-refusing, because plan mode exists to
|
|
49
|
+
// support deep research and the explorer agent is the cheapest way to do bulk
|
|
50
|
+
// searching without flooding the main context. Blocking `task` would have made
|
|
51
|
+
// the mode's headline use case worse, for no security gain.
|
|
52
|
+
'task',
|
|
53
|
+
// VS Code language server — all pure queries.
|
|
54
|
+
'get_symbols', 'get_workspace_symbols', 'find_references', 'go_to_definition',
|
|
55
|
+
'get_hover', 'get_diagnostics',
|
|
56
|
+
// Reading output from an ALREADY-running background shell. Starting one is
|
|
57
|
+
// gated with the rest of bash below; draining a buffer is not a new effect.
|
|
58
|
+
'bash_output',
|
|
59
|
+
]);
|
|
60
|
+
/**
|
|
61
|
+
* Commands allowed through `bash` in plan mode.
|
|
62
|
+
*
|
|
63
|
+
* bash is the hard case: it is one tool that spans `git log` and `rm -rf /`,
|
|
64
|
+
* so plan mode is only as strong as this list. Hence a strict allowlist of
|
|
65
|
+
* verbs known to be read-only, plus the argument screening in
|
|
66
|
+
* `isReadOnlyCommand` for the several that are read-only ONLY in some forms.
|
|
67
|
+
*/
|
|
68
|
+
const READ_ONLY_BASH = new Set([
|
|
69
|
+
'ls', 'cat', 'head', 'tail', 'wc', 'file', 'stat', 'du', 'df', 'pwd', 'which',
|
|
70
|
+
'type', 'echo', 'printf', 'basename', 'dirname', 'realpath', 'readlink',
|
|
71
|
+
'grep', 'egrep', 'fgrep', 'rg', 'ag', 'ack', 'find', 'fd', 'locate',
|
|
72
|
+
'diff', 'comm', 'cmp', 'sort', 'uniq', 'cut', 'tr', 'column', 'jq', 'yq',
|
|
73
|
+
'date', 'whoami', 'hostname', 'uname', 'env', 'printenv', 'id', 'groups',
|
|
74
|
+
'ps', 'top', 'uptime', 'free', 'node', 'python', 'python3',
|
|
75
|
+
'tree', 'less', 'more', 'nl', 'tac', 'strings', 'md5sum', 'sha256sum',
|
|
76
|
+
'true', 'false', 'test', 'sleep', 'seq', 'expr',
|
|
77
|
+
]);
|
|
78
|
+
/**
|
|
79
|
+
* Subcommands that are read-only for tools whose safety depends on the verb.
|
|
80
|
+
*
|
|
81
|
+
* `git` is the reason this exists: `git log` and `git push --force` share one
|
|
82
|
+
* binary, so classifying by executable name alone is useless here.
|
|
83
|
+
*/
|
|
84
|
+
const READ_ONLY_SUBCOMMANDS = {
|
|
85
|
+
git: new Set([
|
|
86
|
+
'log', 'show', 'diff', 'status', 'blame', 'branch', 'tag', 'remote',
|
|
87
|
+
'describe', 'rev-parse', 'rev-list', 'ls-files', 'ls-tree', 'ls-remote',
|
|
88
|
+
'cat-file', 'shortlog', 'reflog', 'whatchanged', 'grep', 'config',
|
|
89
|
+
'check-ignore', 'merge-base', 'name-rev', 'count-objects', 'verify-commit',
|
|
90
|
+
]),
|
|
91
|
+
// Package managers: only their query verbs.
|
|
92
|
+
npm: new Set(['ls', 'list', 'view', 'info', 'outdated', 'why', 'config', 'ping', 'search']),
|
|
93
|
+
pnpm: new Set(['ls', 'list', 'view', 'info', 'outdated', 'why', 'config']),
|
|
94
|
+
yarn: new Set(['list', 'info', 'why', 'config']),
|
|
95
|
+
cargo: new Set(['tree', 'metadata', 'search']),
|
|
96
|
+
go: new Set(['list', 'version', 'env', 'vet', 'doc']),
|
|
97
|
+
docker: new Set(['ps', 'images', 'logs', 'inspect', 'version', 'info', 'top', 'port', 'diff', 'stats']),
|
|
98
|
+
kubectl: new Set(['get', 'describe', 'logs', 'explain', 'top', 'version', 'api-resources', 'api-versions']),
|
|
99
|
+
// gh: read verbs only. `gh run rerun`, `gh pr merge` etc. are excluded, and
|
|
100
|
+
// the nested-verb check in isReadOnlyCommand handles `gh pr view` vs `gh pr merge`.
|
|
101
|
+
gh: new Set(['browse']),
|
|
102
|
+
};
|
|
103
|
+
/** Second-level read verbs for CLIs shaped as `<tool> <noun> <verb>`. */
|
|
104
|
+
const READ_ONLY_NESTED = {
|
|
105
|
+
gh: new Set(['view', 'list', 'status', 'diff', 'checks']),
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Shell metacharacters that can smuggle a second command past verb inspection.
|
|
109
|
+
*
|
|
110
|
+
* We could parse the chain and check each segment — `destructive.ts` does
|
|
111
|
+
* something like that — but plan mode is a deliberate, temporary restriction:
|
|
112
|
+
* the honest answer to "can I run this compound pipeline while frozen?" is
|
|
113
|
+
* "no, and it costs you nothing to wait". Rejecting the whole shape is far
|
|
114
|
+
* easier to get right than parsing shell grammar, and being wrong here means
|
|
115
|
+
* writing to a repo the user thinks is locked.
|
|
116
|
+
*
|
|
117
|
+
* `|` is included: `cat x | tee y` writes, and so does `... | sh`.
|
|
118
|
+
*/
|
|
119
|
+
const SHELL_CONTROL = /[\n\r;&|`]|\$\(|>>|>|<\(/;
|
|
120
|
+
function firstWords(command) {
|
|
121
|
+
return command.trim().split(/\s+/).filter(Boolean);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Is this bash command provably read-only?
|
|
125
|
+
*
|
|
126
|
+
* "Provably" is doing real work: unknown verbs are refused, not guessed at.
|
|
127
|
+
*/
|
|
128
|
+
function isReadOnlyCommand(command) {
|
|
129
|
+
const cmd = command.trim();
|
|
130
|
+
if (!cmd)
|
|
131
|
+
return false;
|
|
132
|
+
// Any chaining/redirection/substitution — refuse the whole thing.
|
|
133
|
+
if (SHELL_CONTROL.test(cmd))
|
|
134
|
+
return false;
|
|
135
|
+
const words = firstWords(cmd);
|
|
136
|
+
if (!words.length)
|
|
137
|
+
return false;
|
|
138
|
+
// `VAR=x cmd` — skip leading environment assignments to find the real verb.
|
|
139
|
+
let i = 0;
|
|
140
|
+
while (i < words.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i]))
|
|
141
|
+
i++;
|
|
142
|
+
if (i >= words.length)
|
|
143
|
+
return false;
|
|
144
|
+
let verb = words[i];
|
|
145
|
+
// Strip a path prefix: /usr/bin/git → git
|
|
146
|
+
const slash = verb.lastIndexOf('/');
|
|
147
|
+
if (slash >= 0)
|
|
148
|
+
verb = verb.slice(slash + 1);
|
|
149
|
+
// `sudo anything` is refused outright regardless of the verb behind it: plan
|
|
150
|
+
// mode is a promise about this machine, and privilege escalation is exactly
|
|
151
|
+
// where a mistaken allow is least recoverable.
|
|
152
|
+
if (verb === 'sudo' || verb === 'doas' || verb === 'su')
|
|
153
|
+
return false;
|
|
154
|
+
const rest = words.slice(i + 1).filter((w) => !w.startsWith('-'));
|
|
155
|
+
const subs = READ_ONLY_SUBCOMMANDS[verb];
|
|
156
|
+
if (subs) {
|
|
157
|
+
const sub = rest[0];
|
|
158
|
+
if (!sub) {
|
|
159
|
+
// Bare `git` / `npm` just prints help — harmless.
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (subs.has(sub)) {
|
|
163
|
+
// `git config --global x y` WRITES. Only the read form (no value) passes.
|
|
164
|
+
if (verb === 'git' && sub === 'config') {
|
|
165
|
+
const args = words.slice(i + 2).filter((w) => !w.startsWith('-'));
|
|
166
|
+
return args.length <= 1;
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
const nested = READ_ONLY_NESTED[verb];
|
|
171
|
+
if (nested && rest[1] && nested.has(rest[1]))
|
|
172
|
+
return true;
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
if (!READ_ONLY_TOOLS.has(verb) && !READ_ONLY_BASH.has(verb))
|
|
176
|
+
return false;
|
|
177
|
+
// Interpreters can execute arbitrary code inline; only allow the trivial
|
|
178
|
+
// read-only forms (`node --version`). `node -e "fs.rmSync(...)"` must not pass.
|
|
179
|
+
if (verb === 'node' || verb === 'python' || verb === 'python3') {
|
|
180
|
+
return words.slice(i + 1).every((w) => w === '--version' || w === '-V' || w === '-v');
|
|
181
|
+
}
|
|
182
|
+
// `find` can execute and delete.
|
|
183
|
+
if (verb === 'find' && words.some((w) => w === '-exec' || w === '-execdir' || w === '-delete')) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
// Reading a file with `test`/`stat` is fine, but `tee` is not in the list at
|
|
187
|
+
// all, and `echo`/`printf` are only safe because redirection is already
|
|
188
|
+
// rejected by SHELL_CONTROL above.
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Should this tool call be refused because the session is in plan mode?
|
|
193
|
+
* Returns null when the call is allowed.
|
|
194
|
+
*/
|
|
195
|
+
function checkPlanMode(tool, input) {
|
|
196
|
+
if (tool === 'bash') {
|
|
197
|
+
const command = typeof input.command === 'string' ? input.command : '';
|
|
198
|
+
// Starting a background process in a "frozen" session is a side effect that
|
|
199
|
+
// outlives the refusal, so it is refused even for an otherwise-safe verb.
|
|
200
|
+
if (input.run_in_background === true) {
|
|
201
|
+
return {
|
|
202
|
+
reason: 'bash-not-read-only',
|
|
203
|
+
message: 'Plan mode is ON: background processes cannot be started. Finish researching and propose ' +
|
|
204
|
+
'your plan; the user will leave plan mode if they want it carried out.',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
if (isReadOnlyCommand(command))
|
|
208
|
+
return null;
|
|
209
|
+
return {
|
|
210
|
+
reason: 'bash-not-read-only',
|
|
211
|
+
message: `Plan mode is ON, so \`bash\` is limited to provably read-only commands and this one was not ` +
|
|
212
|
+
'recognised as such (chained commands, redirection and command substitution are always refused). ' +
|
|
213
|
+
'Do NOT ask the user to approve it and do NOT try a variation to get around this — it is a ' +
|
|
214
|
+
'session-wide lock, not a per-call prompt. Use read-only inspection instead, and put the command ' +
|
|
215
|
+
'in your plan as a step to run once plan mode is off.',
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (READ_ONLY_TOOLS.has(tool))
|
|
219
|
+
return null;
|
|
220
|
+
return {
|
|
221
|
+
reason: 'mutating-tool',
|
|
222
|
+
message: `Plan mode is ON, so \`${tool}\` is unavailable — this session may not modify anything yet. ` +
|
|
223
|
+
'Do NOT ask for approval: no answer the user gives at this prompt can unlock it, because it is a ' +
|
|
224
|
+
'session-wide lock they control directly. Research with read-only tools and finish by proposing ' +
|
|
225
|
+
'a concrete plan (files to change, in order, and how to verify). The user will exit plan mode to ' +
|
|
226
|
+
'let you carry it out.',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/** Text appended to the system prompt while plan mode is active. */
|
|
230
|
+
exports.PLAN_MODE_INSTRUCTIONS = [
|
|
231
|
+
'# PLAN MODE IS ACTIVE',
|
|
232
|
+
'',
|
|
233
|
+
'This session is READ-ONLY. You cannot edit files, write files, run mutating commands, or start',
|
|
234
|
+
'background processes. This is enforced outside your control — it is not a permission prompt, and',
|
|
235
|
+
'the user cannot approve an exception from inside this turn.',
|
|
236
|
+
'',
|
|
237
|
+
'Therefore:',
|
|
238
|
+
'- NEVER ask "shall I go ahead and make this change?" — you cannot, whatever the answer.',
|
|
239
|
+
'- NEVER attempt a mutating tool "just to see" — it will be refused and wastes the turn.',
|
|
240
|
+
'- NEVER try to reach a blocked command another way (a different flag, a script, an interpreter).',
|
|
241
|
+
'',
|
|
242
|
+
'Your job is to research thoroughly, then deliver a plan:',
|
|
243
|
+
'1. What you found — the specific files, functions and line numbers that matter.',
|
|
244
|
+
'2. What you propose to change — file by file, in dependency order.',
|
|
245
|
+
'3. Risks and unknowns — what could break, what you could not verify, what you assumed.',
|
|
246
|
+
'4. How it will be verified — the exact build/test/lint command that proves it works.',
|
|
247
|
+
'',
|
|
248
|
+
'Be concrete. "Update the auth logic" is not a plan; "add a `refreshToken` field to AuthConfig in',
|
|
249
|
+
'auth/index.ts:42, then thread it through client.ts:118" is. The user will review the plan and',
|
|
250
|
+
'leave plan mode to have it carried out.',
|
|
251
|
+
].join('\n');
|
|
252
|
+
//# sourceMappingURL=planMode.js.map
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAA8B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAiErH,eAAO,MAAM,QAAQ,QAAmB,CAAC;AAIzC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5D,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACtD,CAAC,EAAE,CAeL;AAiGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,oFAAoF;IACpF,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACjG,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6IAA6I;IAC7I,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;OAeG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAiDD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAC7B,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAA8B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAiErH,eAAO,MAAM,QAAQ,QAAmB,CAAC;AAIzC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5D,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACtD,CAAC,EAAE,CAeL;AAiGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,oFAAoF;IACpF,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACjG,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6IAA6I;IAC7I,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;OAeG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAiDD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAC7B,OAAO,CAAC,OAAO,CAAC,CAwlClB;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYxD;AAID,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA0BlD;AAID,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B1E;AAID,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BhF"}
|