xiaotime 0.2.0 → 0.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/dist/__tests__/approval_menu.test.d.ts +15 -0
- package/dist/__tests__/approval_menu.test.d.ts.map +1 -0
- package/dist/__tests__/approval_menu.test.js +107 -0
- package/dist/__tests__/approval_menu.test.js.map +1 -0
- package/dist/__tests__/server_tool_render.test.d.ts +17 -0
- package/dist/__tests__/server_tool_render.test.d.ts.map +1 -0
- package/dist/__tests__/server_tool_render.test.js +74 -0
- package/dist/__tests__/server_tool_render.test.js.map +1 -0
- package/dist/__tests__/settings.test.d.ts +16 -0
- package/dist/__tests__/settings.test.d.ts.map +1 -0
- package/dist/__tests__/settings.test.js +289 -0
- package/dist/__tests__/settings.test.js.map +1 -0
- package/dist/__tests__/tools.test.d.ts +17 -0
- package/dist/__tests__/tools.test.d.ts.map +1 -0
- package/dist/__tests__/tools.test.js +381 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +6 -2
- package/dist/auth.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -1
- package/dist/config.js.map +1 -1
- package/dist/display.d.ts +19 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +23 -0
- package/dist/display.js.map +1 -1
- package/dist/settings.d.ts +109 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +332 -0
- package/dist/settings.js.map +1 -0
- package/dist/tools.d.ts +11 -3
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +96 -33
- package/dist/tools.js.map +1 -1
- package/dist/ui_state.d.ts +134 -0
- package/dist/ui_state.d.ts.map +1 -0
- package/dist/ui_state.js +460 -0
- package/dist/ui_state.js.map +1 -0
- package/dist/ws.d.ts +5 -0
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +99 -66
- package/dist/ws.js.map +1 -1
- package/package.json +5 -2
package/dist/tools.js
CHANGED
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Local tool execution + approval gate.
|
|
4
4
|
*
|
|
5
|
-
* All tools execute on Harvey's machine. write_file
|
|
6
|
-
*
|
|
5
|
+
* All tools execute on Harvey's machine. write_file, shell_command,
|
|
6
|
+
* and git_commit pass through `_gateApproval` which checks the
|
|
7
|
+
* persisted allowlist (`~/.xiaotime/settings.json`) before prompting.
|
|
8
|
+
* Matching allowlist entries short-circuit the menu; the post-execute
|
|
9
|
+
* status line is suffixed with ` (auto-approved)` so the user can
|
|
10
|
+
* see which calls bypassed the prompt (ISC-6509-004).
|
|
11
|
+
*
|
|
12
|
+
* Read-only tools (`read_file`, `list_directory`, `git_status`,
|
|
13
|
+
* `git_diff`) never gate (ISC-6509-006).
|
|
7
14
|
*/
|
|
8
15
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
16
|
if (k2 === undefined) k2 = k;
|
|
@@ -47,9 +54,9 @@ exports.executeTool = executeTool;
|
|
|
47
54
|
const fs = __importStar(require("fs"));
|
|
48
55
|
const path = __importStar(require("path"));
|
|
49
56
|
const child_process = __importStar(require("child_process"));
|
|
50
|
-
const readline = __importStar(require("readline"));
|
|
51
57
|
const diff_1 = require("diff");
|
|
52
58
|
const chalk_1 = __importDefault(require("chalk"));
|
|
59
|
+
const settings_js_1 = require("./settings.js");
|
|
53
60
|
// Session cwd — set on connect
|
|
54
61
|
let sessionCwd = process.cwd();
|
|
55
62
|
function setSessionCwd(cwd) {
|
|
@@ -58,19 +65,59 @@ function setSessionCwd(cwd) {
|
|
|
58
65
|
function resolvePath(p) {
|
|
59
66
|
return path.isAbsolute(p) ? p : path.resolve(sessionCwd, p);
|
|
60
67
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Approval gate for the 3 prompting client-side tools. Checks the
|
|
70
|
+
* persisted allowlist first; if no match, prompts via the
|
|
71
|
+
* SessionUI menu; if the user chose "Run and don't ask again",
|
|
72
|
+
* persists the derived pattern.
|
|
73
|
+
*
|
|
74
|
+
* The header is printed in both paths (allowlist hit + menu prompt)
|
|
75
|
+
* so the user always sees what's about to run. The `(auto-approved)`
|
|
76
|
+
* indicator is appended to the caller's post-execute status line —
|
|
77
|
+
* not added by this helper — so tool-specific status text
|
|
78
|
+
* (`✓ Written` / `✓ Ran` / `✓ Committed`) stays where the tool
|
|
79
|
+
* defines it.
|
|
80
|
+
*/
|
|
81
|
+
async function _gateApproval(ui, tool, input, header) {
|
|
82
|
+
const allowlist = (0, settings_js_1.loadAllowlist)();
|
|
83
|
+
const match = (0, settings_js_1.matchAllowlist)(tool, input, allowlist);
|
|
84
|
+
if (match) {
|
|
85
|
+
// Print the header so the user sees what's about to run, then
|
|
86
|
+
// short-circuit the menu.
|
|
87
|
+
process.stdout.write(header);
|
|
88
|
+
return { approved: true, autoApproved: true };
|
|
89
|
+
}
|
|
90
|
+
const result = await ui.promptApprovalMenu(header);
|
|
91
|
+
if (!result.approved) {
|
|
92
|
+
return { approved: false, rejectReason: result.rejectReason };
|
|
93
|
+
}
|
|
94
|
+
if (result.allowlistRequested) {
|
|
95
|
+
const pattern = (0, settings_js_1.derivePattern)(tool, input);
|
|
96
|
+
if (pattern !== null) {
|
|
97
|
+
// #6538 CR-r1: wrap the persist call so a disk-full /
|
|
98
|
+
// permission-denied / chmod failure doesn't abort the tool
|
|
99
|
+
// run. The user already approved the action; the allowlist
|
|
100
|
+
// write is a UX convenience, not a correctness gate. Log a
|
|
101
|
+
// yellow warning to stderr so the failure isn't silent.
|
|
102
|
+
try {
|
|
103
|
+
(0, settings_js_1.appendAllowlist)({ tool, pattern });
|
|
104
|
+
process.stdout.write(chalk_1.default.dim(` (allowlist updated: ${tool} → ${pattern})\n`));
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
108
|
+
process.stderr.write(chalk_1.default.yellow(` (failed to persist allowlist: ${msg})\n`));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { approved: true, autoApproved: false };
|
|
113
|
+
}
|
|
114
|
+
function _approvedSuffix(gate) {
|
|
115
|
+
if (gate.approved && gate.autoApproved) {
|
|
116
|
+
return chalk_1.default.dim(" (auto-approved)");
|
|
117
|
+
}
|
|
118
|
+
return "";
|
|
72
119
|
}
|
|
73
|
-
async function executeTool(call) {
|
|
120
|
+
async function executeTool(call, ui) {
|
|
74
121
|
const { tool_use_id, name, input } = call;
|
|
75
122
|
try {
|
|
76
123
|
switch (name) {
|
|
@@ -101,15 +148,20 @@ async function executeTool(call) {
|
|
|
101
148
|
return chalk_1.default.red(l);
|
|
102
149
|
return chalk_1.default.dim(l);
|
|
103
150
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
if (!approved) {
|
|
108
|
-
|
|
151
|
+
const header = chalk_1.default.yellow(`\n[write_file] ${filePath}\n`) +
|
|
152
|
+
colored.join("\n") + "\n";
|
|
153
|
+
const gate = await _gateApproval(ui, "write_file", input, header);
|
|
154
|
+
if (!gate.approved) {
|
|
155
|
+
const tail = gate.rejectReason ? `: ${gate.rejectReason}` : ".";
|
|
156
|
+
return {
|
|
157
|
+
tool_use_id,
|
|
158
|
+
content: `Rejected by user${tail}`,
|
|
159
|
+
is_error: false,
|
|
160
|
+
};
|
|
109
161
|
}
|
|
110
162
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
111
163
|
fs.writeFileSync(filePath, newContent, "utf-8");
|
|
112
|
-
console.log(chalk_1.default.green(` ✓ Written`));
|
|
164
|
+
console.log(chalk_1.default.green(` ✓ Written`) + _approvedSuffix(gate));
|
|
113
165
|
return { tool_use_id, content: `File written: ${filePath}`, is_error: false };
|
|
114
166
|
}
|
|
115
167
|
case "list_directory": {
|
|
@@ -137,11 +189,16 @@ async function executeTool(call) {
|
|
|
137
189
|
case "shell_command": {
|
|
138
190
|
const command = input.command;
|
|
139
191
|
const cwd = input.cwd ? resolvePath(input.cwd) : sessionCwd;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
if (!approved) {
|
|
144
|
-
|
|
192
|
+
const header = chalk_1.default.yellow(`\n[shell_command] ${command}\n`) +
|
|
193
|
+
chalk_1.default.dim(` cwd: ${cwd}\n`);
|
|
194
|
+
const gate = await _gateApproval(ui, "shell_command", input, header);
|
|
195
|
+
if (!gate.approved) {
|
|
196
|
+
const tail = gate.rejectReason ? `: ${gate.rejectReason}` : ".";
|
|
197
|
+
return {
|
|
198
|
+
tool_use_id,
|
|
199
|
+
content: `Rejected by user${tail}`,
|
|
200
|
+
is_error: false,
|
|
201
|
+
};
|
|
145
202
|
}
|
|
146
203
|
const result = child_process.execSync(command, {
|
|
147
204
|
cwd,
|
|
@@ -149,6 +206,7 @@ async function executeTool(call) {
|
|
|
149
206
|
stdio: ["pipe", "pipe", "pipe"],
|
|
150
207
|
timeout: 60000,
|
|
151
208
|
});
|
|
209
|
+
console.log(chalk_1.default.green(` ✓ Ran`) + _approvedSuffix(gate));
|
|
152
210
|
console.log(chalk_1.default.dim(result.slice(0, 500)));
|
|
153
211
|
return { tool_use_id, content: result, is_error: false };
|
|
154
212
|
}
|
|
@@ -179,15 +237,20 @@ async function executeTool(call) {
|
|
|
179
237
|
cwd: sessionCwd,
|
|
180
238
|
encoding: "utf-8",
|
|
181
239
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
if (!approved) {
|
|
187
|
-
|
|
240
|
+
const header = chalk_1.default.yellow(`\n[git_commit]\n`) +
|
|
241
|
+
chalk_1.default.dim(`Staged:\n${staged}\n`) +
|
|
242
|
+
chalk_1.default.dim(`Message: ${message}\n`);
|
|
243
|
+
const gate = await _gateApproval(ui, "git_commit", input, header);
|
|
244
|
+
if (!gate.approved) {
|
|
245
|
+
const tail = gate.rejectReason ? `: ${gate.rejectReason}` : ".";
|
|
246
|
+
return {
|
|
247
|
+
tool_use_id,
|
|
248
|
+
content: `Rejected by user${tail}`,
|
|
249
|
+
is_error: false,
|
|
250
|
+
};
|
|
188
251
|
}
|
|
189
252
|
const out = child_process.execSync(`git commit -m ${JSON.stringify(message)}`, { cwd: sessionCwd, encoding: "utf-8" });
|
|
190
|
-
console.log(chalk_1.default.green(` ✓ Committed`));
|
|
253
|
+
console.log(chalk_1.default.green(` ✓ Committed`) + _approvedSuffix(gate));
|
|
191
254
|
return { tool_use_id, content: out, is_error: false };
|
|
192
255
|
}
|
|
193
256
|
default:
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-UI state machine for the xiaotime dev CLI.
|
|
3
|
+
*
|
|
4
|
+
* SPRINT-CLI-STATE-MACHINE-1 (#6163 / closes #6127) shipped the original
|
|
5
|
+
* state machine + raw-mode approval prompt. That fix eliminated the
|
|
6
|
+
* defaults-to-N half of the "yy" double-echo bug but the visible-yy half
|
|
7
|
+
* persisted because `readline.createInterface({ terminal: true })` attaches
|
|
8
|
+
* its own keypress handler to stdin that echoes characters via its own
|
|
9
|
+
* stdout writes; `rl.pause()` stops `line` events but does NOT detach that
|
|
10
|
+
* echo path, and `setRawMode(true)` only suppresses kernel-level echo, not
|
|
11
|
+
* readline's.
|
|
12
|
+
*
|
|
13
|
+
* SPRINT-CLI-APPROVAL-MENU-1 (#6509) replaces `promptApproval`'s `[y/N]`
|
|
14
|
+
* one-shot prompt with `promptApprovalMenu` — a three-option numbered menu
|
|
15
|
+
* (Run / Run + allowlist / Reject + feedback). The rl is explicitly
|
|
16
|
+
* **closed and recreated** around the menu render so its keypress echo
|
|
17
|
+
* physically can't fire (the rl object is gone for the duration of the
|
|
18
|
+
* menu). Persistent close listeners survive the recreation via
|
|
19
|
+
* `onRlClose()` — callers that need a stable close hook register through
|
|
20
|
+
* that instead of `getRl().on("close", ...)`.
|
|
21
|
+
*
|
|
22
|
+
* The state machine has four states:
|
|
23
|
+
*
|
|
24
|
+
* IDLE — at the `you:` prompt, awaiting user input.
|
|
25
|
+
* GENERATING — model is streaming tokens (or about to). Spinner.
|
|
26
|
+
* RUNNING_TOOL — a server-side tool is running. Spinner.
|
|
27
|
+
* AWAITING_APPROVAL — user must navigate the approval menu for a
|
|
28
|
+
* client-side tool. Main rl is closed; raw stdin
|
|
29
|
+
* captures keystrokes.
|
|
30
|
+
*
|
|
31
|
+
* The WS handler in `ws.ts` is the sole driver. Transitions:
|
|
32
|
+
*
|
|
33
|
+
* IDLE -- user line received -> GENERATING
|
|
34
|
+
* GENERATING -- text_delta -> GENERATING (refresh)
|
|
35
|
+
* GENERATING -- tool_call (server) -> RUNNING_TOOL
|
|
36
|
+
* GENERATING -- tool_call (client+approval) -> AWAITING_APPROVAL
|
|
37
|
+
* AWAITING_APPROVAL -- menu selection -> RUNNING_TOOL
|
|
38
|
+
* RUNNING_TOOL -- tool_result sent -> GENERATING
|
|
39
|
+
* GENERATING -- message_stop -> IDLE
|
|
40
|
+
* ANY -- error -> IDLE
|
|
41
|
+
*/
|
|
42
|
+
import * as readline from "readline";
|
|
43
|
+
export type CliState = "idle" | "generating" | "running_tool" | "awaiting_approval";
|
|
44
|
+
export type ApprovalMenuResult = {
|
|
45
|
+
approved: true;
|
|
46
|
+
allowlistRequested: boolean;
|
|
47
|
+
} | {
|
|
48
|
+
approved: false;
|
|
49
|
+
rejectReason: string;
|
|
50
|
+
};
|
|
51
|
+
export declare class SessionUI {
|
|
52
|
+
private state;
|
|
53
|
+
private spinnerTimer;
|
|
54
|
+
private spinnerFrame;
|
|
55
|
+
private spinnerStartedAt;
|
|
56
|
+
private spinnerLabel;
|
|
57
|
+
private spinnerLineDirty;
|
|
58
|
+
private rl;
|
|
59
|
+
private lineListener;
|
|
60
|
+
/**
|
|
61
|
+
* Close-listener callbacks that should survive rl recreations. The
|
|
62
|
+
* approval-menu path closes + recreates `rl` to physically detach
|
|
63
|
+
* readline's keypress echo. ws.ts registers its "Session paused"
|
|
64
|
+
* resume hint here so it stays attached across recreations.
|
|
65
|
+
*/
|
|
66
|
+
private closeListeners;
|
|
67
|
+
constructor();
|
|
68
|
+
/** Hand the underlying readline to callers that need it for cleanup. */
|
|
69
|
+
getRl(): readline.Interface;
|
|
70
|
+
/**
|
|
71
|
+
* Register a callback to fire when the rl reports a non-suppressed
|
|
72
|
+
* `close` event (the only one users observe is Ctrl+C at the main
|
|
73
|
+
* prompt — close-during-approval is suppressed via removeAllListeners
|
|
74
|
+
* before `rl.close()`). Callbacks are re-attached on every rl
|
|
75
|
+
* recreation so they outlive `promptApprovalMenu`.
|
|
76
|
+
*/
|
|
77
|
+
onRlClose(listener: () => void): void;
|
|
78
|
+
/** Set the explicit current state. Drives spinner start/stop. */
|
|
79
|
+
setState(next: CliState): void;
|
|
80
|
+
getState(): CliState;
|
|
81
|
+
/** Wait for one line of user input on the main rl. */
|
|
82
|
+
promptLine(): Promise<string>;
|
|
83
|
+
/**
|
|
84
|
+
* Three-option numbered approval menu. Replaces the pre-#6509
|
|
85
|
+
* `[y/N]` one-shot prompt.
|
|
86
|
+
*
|
|
87
|
+
* Visual:
|
|
88
|
+
* ❯ 1. Run
|
|
89
|
+
* 2. Run and don't ask again
|
|
90
|
+
* 3. Reject and tell Claude why
|
|
91
|
+
* (1-3, ↑↓ Enter, Esc to reject)
|
|
92
|
+
*
|
|
93
|
+
* Controls:
|
|
94
|
+
* - Number key 1/2/3 — one-shot select
|
|
95
|
+
* - Arrow Up/Down — move focus
|
|
96
|
+
* - Enter — select focused
|
|
97
|
+
* - Esc — equivalent to option 3 (reject)
|
|
98
|
+
* - Ctrl+C — reject + propagate SIGINT (cancels session)
|
|
99
|
+
*
|
|
100
|
+
* The rl is closed before the menu render and recreated after. This
|
|
101
|
+
* physically removes readline's keypress echo from stdin for the
|
|
102
|
+
* duration of the menu — the bug fix the #6163 patch attempted via
|
|
103
|
+
* `rl.pause()` (which only stops `line` events, not the keypress
|
|
104
|
+
* echo). Persistent close listeners are stashed in
|
|
105
|
+
* `this.closeListeners` and re-attached on recreate; the close event
|
|
106
|
+
* triggered by THIS close() is suppressed via removeAllListeners
|
|
107
|
+
* before the call so it doesn't fire the "Session paused" hint.
|
|
108
|
+
*
|
|
109
|
+
* For option 3, after the menu resolves the recreated rl prompts
|
|
110
|
+
* once for a free-form rejection reason (line-mode). Empty input is
|
|
111
|
+
* allowed.
|
|
112
|
+
*
|
|
113
|
+
* The returned `allowlistRequested: true` (option 2) is a signal to
|
|
114
|
+
* the caller — PR2 wires it to write the pattern to
|
|
115
|
+
* `~/.xiaotime/settings.json`. PR1 callers may ignore it.
|
|
116
|
+
*/
|
|
117
|
+
promptApprovalMenu(toolHeader?: string): Promise<ApprovalMenuResult>;
|
|
118
|
+
private _makeRl;
|
|
119
|
+
private _renderMenuAndGetSelection;
|
|
120
|
+
/** Total lines the menu occupies: one per option + one hint line. */
|
|
121
|
+
private _menuLineCount;
|
|
122
|
+
private _renderMenu;
|
|
123
|
+
private _rerenderMenu;
|
|
124
|
+
private _clearMenu;
|
|
125
|
+
private startSpinner;
|
|
126
|
+
private renderSpinnerFrame;
|
|
127
|
+
private stopSpinner;
|
|
128
|
+
/** Called by the text_delta renderer the first time a real model
|
|
129
|
+
* token arrives during a `generating` state. Clears the spinner so
|
|
130
|
+
* the token prints cleanly, but leaves the state at `generating`
|
|
131
|
+
* (token streaming continues without re-spinning). */
|
|
132
|
+
onFirstToken(): void;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=ui_state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui_state.d.ts","sourceRoot":"","sources":["../src/ui_state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAGrC,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,YAAY,GACZ,cAAc,GACd,mBAAmB,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAa9C,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,YAAY,CAAM;IAK1B,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,EAAE,CAAqB;IAC/B,OAAO,CAAC,YAAY,CAAyC;IAC7D;;;;;OAKG;IACH,OAAO,CAAC,cAAc,CAAyB;;IAM/C,wEAAwE;IACxE,KAAK,IAAI,QAAQ,CAAC,SAAS;IAI3B;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAKrC,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAoB9B,QAAQ,IAAI,QAAQ;IAIpB,sDAAsD;IACtD,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAe7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACG,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgD1E,OAAO,CAAC,OAAO;YAYD,0BAA0B;IAmIxC,qEAAqE;IACrE,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,WAAW;IAYnB;;;0DAGsD;IACtD,YAAY,IAAI,IAAI;CAUrB"}
|