brosh 0.2.2
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/LICENSE +21 -0
- package/README.md +181 -0
- package/brosh_brandmark.svg +3 -0
- package/brosh_logo.svg +27 -0
- package/cli_icon.svg +52 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +138 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +618 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +25 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +28 -0
- package/dist/lib.js.map +1 -0
- package/dist/mode-selector.d.ts +7 -0
- package/dist/mode-selector.d.ts.map +1 -0
- package/dist/mode-selector.js +138 -0
- package/dist/mode-selector.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +79 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/recording/index.d.ts +4 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/manager.d.ts +62 -0
- package/dist/recording/manager.d.ts.map +1 -0
- package/dist/recording/manager.js +123 -0
- package/dist/recording/manager.js.map +1 -0
- package/dist/recording/recorder.d.ts +95 -0
- package/dist/recording/recorder.d.ts.map +1 -0
- package/dist/recording/recorder.js +330 -0
- package/dist/recording/recorder.js.map +1 -0
- package/dist/recording/types.d.ts +65 -0
- package/dist/recording/types.d.ts.map +1 -0
- package/dist/recording/types.js +2 -0
- package/dist/recording/types.js.map +1 -0
- package/dist/sandbox/ModeSelector.d.ts +2 -0
- package/dist/sandbox/ModeSelector.d.ts.map +1 -0
- package/dist/sandbox/ModeSelector.js +2 -0
- package/dist/sandbox/ModeSelector.js.map +1 -0
- package/dist/sandbox/config.d.ts +46 -0
- package/dist/sandbox/config.d.ts.map +1 -0
- package/dist/sandbox/config.js +144 -0
- package/dist/sandbox/config.js.map +1 -0
- package/dist/sandbox/controller.d.ts +72 -0
- package/dist/sandbox/controller.d.ts.map +1 -0
- package/dist/sandbox/controller.js +208 -0
- package/dist/sandbox/controller.js.map +1 -0
- package/dist/sandbox/index.d.ts +6 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/mode-prompt.d.ts +10 -0
- package/dist/sandbox/mode-prompt.d.ts.map +1 -0
- package/dist/sandbox/mode-prompt.js +130 -0
- package/dist/sandbox/mode-prompt.js.map +1 -0
- package/dist/sandbox/prompt.d.ts +10 -0
- package/dist/sandbox/prompt.d.ts.map +1 -0
- package/dist/sandbox/prompt.js +434 -0
- package/dist/sandbox/prompt.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +59 -0
- package/dist/server.js.map +1 -0
- package/dist/terminal/index.d.ts +5 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +3 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/manager.d.ts +153 -0
- package/dist/terminal/manager.d.ts.map +1 -0
- package/dist/terminal/manager.js +276 -0
- package/dist/terminal/manager.js.map +1 -0
- package/dist/terminal/session.d.ts +137 -0
- package/dist/terminal/session.d.ts.map +1 -0
- package/dist/terminal/session.js +752 -0
- package/dist/terminal/session.js.map +1 -0
- package/dist/tools/definitions.d.ts +18 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +114 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/getContent.d.ts +32 -0
- package/dist/tools/getContent.d.ts.map +1 -0
- package/dist/tools/getContent.js +38 -0
- package/dist/tools/getContent.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +49 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/screenshot.d.ts +20 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +28 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/sendKey.d.ts +31 -0
- package/dist/tools/sendKey.d.ts.map +1 -0
- package/dist/tools/sendKey.js +38 -0
- package/dist/tools/sendKey.js.map +1 -0
- package/dist/tools/startRecording.d.ts +68 -0
- package/dist/tools/startRecording.d.ts.map +1 -0
- package/dist/tools/startRecording.js +111 -0
- package/dist/tools/startRecording.js.map +1 -0
- package/dist/tools/stopRecording.d.ts +31 -0
- package/dist/tools/stopRecording.d.ts.map +1 -0
- package/dist/tools/stopRecording.js +76 -0
- package/dist/tools/stopRecording.js.map +1 -0
- package/dist/tools/type.d.ts +31 -0
- package/dist/tools/type.d.ts.map +1 -0
- package/dist/tools/type.js +31 -0
- package/dist/tools/type.js.map +1 -0
- package/dist/transport/gui-protocol.d.ts +163 -0
- package/dist/transport/gui-protocol.d.ts.map +1 -0
- package/dist/transport/gui-protocol.js +68 -0
- package/dist/transport/gui-protocol.js.map +1 -0
- package/dist/transport/gui-stream.d.ts +139 -0
- package/dist/transport/gui-stream.d.ts.map +1 -0
- package/dist/transport/gui-stream.js +440 -0
- package/dist/transport/gui-stream.js.map +1 -0
- package/dist/transport/index.d.ts +6 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +6 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/socket.d.ts +46 -0
- package/dist/transport/socket.d.ts.map +1 -0
- package/dist/transport/socket.js +310 -0
- package/dist/transport/socket.js.map +1 -0
- package/dist/types/mcp-client-info.d.ts +226 -0
- package/dist/types/mcp-client-info.d.ts.map +1 -0
- package/dist/types/mcp-client-info.js +62 -0
- package/dist/types/mcp-client-info.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +84 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/utils/env.d.ts +17 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +35 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/keys.d.ts +16 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +155 -0
- package/dist/utils/keys.js.map +1 -0
- package/dist/utils/platform.d.ts +16 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +41 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/session-logger.d.ts +31 -0
- package/dist/utils/session-logger.d.ts.map +1 -0
- package/dist/utils/session-logger.js +125 -0
- package/dist/utils/session-logger.js.map +1 -0
- package/dist/utils/stats.d.ts +46 -0
- package/dist/utils/stats.d.ts.map +1 -0
- package/dist/utils/stats.js +89 -0
- package/dist/utils/stats.js.map +1 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +9 -0
- package/dist/utils/version.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +61 -0
- package/packages/desktop-electron/THIRD-PARTY-NOTICES +56 -0
- package/packages/desktop-electron/build/afterPack.cjs +147 -0
- package/packages/desktop-electron/package-lock.json +10071 -0
- package/packages/desktop-electron/package.json +170 -0
- package/packages/desktop-electron/resources/icons/mac/icon.icns +0 -0
- package/packages/desktop-electron/resources/icons/png/1024x1024.png +0 -0
- package/packages/desktop-electron/resources/icons/png/128x128.png +0 -0
- package/packages/desktop-electron/resources/icons/png/16x16.png +0 -0
- package/packages/desktop-electron/resources/icons/png/24x24.png +0 -0
- package/packages/desktop-electron/resources/icons/png/256x256.png +0 -0
- package/packages/desktop-electron/resources/icons/png/32x32.png +0 -0
- package/packages/desktop-electron/resources/icons/png/48x48.png +0 -0
- package/packages/desktop-electron/resources/icons/png/512x512.png +0 -0
- package/packages/desktop-electron/resources/icons/png/64x64.png +0 -0
- package/packages/desktop-electron/resources/icons/win/icon.ico +0 -0
- package/packages/desktop-electron/scripts/download-models.js +97 -0
- package/packages/desktop-electron/scripts/prepare-sandbox-bins.js +186 -0
- package/packages/desktop-electron/tests/main/ai-detection/additionalFunctions.test.ts +224 -0
- package/packages/desktop-electron/tests/main/ai-detection/checkOverridePrefix.test.ts +162 -0
- package/packages/desktop-electron/tests/main/ai-detection/classifyInput.test.ts +132 -0
- package/packages/desktop-electron/tests/main/ai-detection/detectTypos.test.ts +342 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/commands.ts +134 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/natural-language.ts +133 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/typos.ts +123 -0
- package/packages/desktop-electron/tests/main/ai-detection/hasValidSubcommand.test.ts +218 -0
- package/packages/desktop-electron/tests/main/ai-detection/isCommandNotFound.test.ts +117 -0
- package/packages/desktop-electron/tests/main/error-triage/buildTriagePrompt.test.ts +133 -0
- package/packages/desktop-electron/tests/main/error-triage/parseTriageResponse.test.ts +123 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/battery-optimization.test.ts +243 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/command-fast-track.test.ts +292 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/default-cwd.test.ts +70 -0
- package/packages/desktop-electron/tests/setup.ts +274 -0
- package/packages/desktop-electron/tsconfig.json +18 -0
- package/packages/desktop-electron/tsconfig.main.json +20 -0
- package/packages/desktop-electron/vite.config.ts +19 -0
- package/packages/desktop-electron/vitest.config.ts +18 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Recorder handles writing asciicast v2 format recordings
|
|
6
|
+
*
|
|
7
|
+
* Asciicast v2 format:
|
|
8
|
+
* - First line: JSON header with version, dimensions, timestamp
|
|
9
|
+
* - Subsequent lines: JSON arrays [time, type, data]
|
|
10
|
+
* - time: seconds since start (float)
|
|
11
|
+
* - type: "o" for output, "r" for resize
|
|
12
|
+
* - data: string content
|
|
13
|
+
*/
|
|
14
|
+
export class Recorder {
|
|
15
|
+
id;
|
|
16
|
+
mode;
|
|
17
|
+
format;
|
|
18
|
+
outputDir;
|
|
19
|
+
tempPath;
|
|
20
|
+
finalPath;
|
|
21
|
+
writeStream = null;
|
|
22
|
+
startTime = 0;
|
|
23
|
+
bytesWritten = 0;
|
|
24
|
+
finalized = false;
|
|
25
|
+
idleTimeLimit;
|
|
26
|
+
lastEventTime = 0;
|
|
27
|
+
adjustedElapsed = 0;
|
|
28
|
+
// Timeout settings
|
|
29
|
+
maxDuration;
|
|
30
|
+
inactivityTimeout;
|
|
31
|
+
maxDurationTimer = null;
|
|
32
|
+
inactivityTimer = null;
|
|
33
|
+
stopReason = 'explicit';
|
|
34
|
+
// Callback for auto-finalize events
|
|
35
|
+
onAutoFinalize;
|
|
36
|
+
constructor(id, mode, outputDir, format = 'v2', idleTimeLimit = 2, maxDuration = 3600, // 60 minutes default
|
|
37
|
+
inactivityTimeout = 600 // 10 minutes default
|
|
38
|
+
) {
|
|
39
|
+
this.id = id;
|
|
40
|
+
this.mode = mode;
|
|
41
|
+
this.format = format;
|
|
42
|
+
this.outputDir = outputDir;
|
|
43
|
+
this.idleTimeLimit = idleTimeLimit;
|
|
44
|
+
this.maxDuration = maxDuration;
|
|
45
|
+
this.inactivityTimeout = inactivityTimeout;
|
|
46
|
+
// Generate temp and final paths
|
|
47
|
+
const timestamp = Date.now();
|
|
48
|
+
const filename = `terminal-${timestamp}-${id}.cast`;
|
|
49
|
+
this.tempPath = path.join(os.tmpdir(), `brosh-recording-${id}.cast`);
|
|
50
|
+
this.finalPath = path.join(outputDir, filename);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start the recording
|
|
54
|
+
* Writes the asciicast header to the temp file
|
|
55
|
+
*/
|
|
56
|
+
start(width, height, env) {
|
|
57
|
+
if (this.writeStream) {
|
|
58
|
+
throw new Error("Recording already started");
|
|
59
|
+
}
|
|
60
|
+
this.startTime = Date.now();
|
|
61
|
+
// Ensure output directory exists
|
|
62
|
+
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
63
|
+
// Create write stream to temp file
|
|
64
|
+
this.writeStream = fs.createWriteStream(this.tempPath, { flags: 'w' });
|
|
65
|
+
// Write header
|
|
66
|
+
const header = {
|
|
67
|
+
version: 2,
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
timestamp: Math.floor(this.startTime / 1000),
|
|
71
|
+
};
|
|
72
|
+
if (env) {
|
|
73
|
+
header.env = env;
|
|
74
|
+
}
|
|
75
|
+
this.writeLine(JSON.stringify(header));
|
|
76
|
+
// Set up max duration timer
|
|
77
|
+
if (this.maxDuration > 0) {
|
|
78
|
+
this.maxDurationTimer = setTimeout(() => {
|
|
79
|
+
this._autoFinalize('max_duration');
|
|
80
|
+
}, this.maxDuration * 1000);
|
|
81
|
+
// Prevent timer from keeping process alive
|
|
82
|
+
this.maxDurationTimer.unref();
|
|
83
|
+
}
|
|
84
|
+
// Set up initial inactivity timer
|
|
85
|
+
if (this.inactivityTimeout > 0) {
|
|
86
|
+
this.inactivityTimer = setTimeout(() => {
|
|
87
|
+
this._autoFinalize('inactivity');
|
|
88
|
+
}, this.inactivityTimeout * 1000);
|
|
89
|
+
// Prevent timer from keeping process alive
|
|
90
|
+
this.inactivityTimer.unref();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Record output data
|
|
95
|
+
*/
|
|
96
|
+
recordOutput(data) {
|
|
97
|
+
if (!this.writeStream || this.finalized) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Reset inactivity timer on each output event
|
|
101
|
+
if (this.inactivityTimeout > 0 && this.inactivityTimer) {
|
|
102
|
+
clearTimeout(this.inactivityTimer);
|
|
103
|
+
this.inactivityTimer = setTimeout(() => {
|
|
104
|
+
this._autoFinalize('inactivity');
|
|
105
|
+
}, this.inactivityTimeout * 1000);
|
|
106
|
+
// Prevent timer from keeping process alive
|
|
107
|
+
this.inactivityTimer.unref();
|
|
108
|
+
}
|
|
109
|
+
const elapsed = this.getElapsedSeconds();
|
|
110
|
+
const event = [elapsed, 'o', data];
|
|
111
|
+
this.writeLine(JSON.stringify(event));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Record terminal resize event
|
|
115
|
+
*/
|
|
116
|
+
recordResize(cols, rows) {
|
|
117
|
+
if (!this.writeStream || this.finalized) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const elapsed = this.getElapsedSeconds();
|
|
121
|
+
const event = [elapsed, 'r', `${cols}x${rows}`];
|
|
122
|
+
this.writeLine(JSON.stringify(event));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Finalize the recording
|
|
126
|
+
* - For 'always' mode: move temp file to output dir
|
|
127
|
+
* - For 'on-failure' mode: move if exitCode !== 0, delete otherwise
|
|
128
|
+
*
|
|
129
|
+
* Returns metadata about the recording
|
|
130
|
+
*/
|
|
131
|
+
async finalize(exitCode, stopReason) {
|
|
132
|
+
if (this.finalized) {
|
|
133
|
+
throw new Error("Recording already finalized");
|
|
134
|
+
}
|
|
135
|
+
this.finalized = true;
|
|
136
|
+
const endTime = Date.now();
|
|
137
|
+
const durationMs = endTime - this.startTime;
|
|
138
|
+
// Clear any active timers
|
|
139
|
+
this.clearTimers();
|
|
140
|
+
// Use provided stopReason or the internally tracked one
|
|
141
|
+
const finalStopReason = stopReason ?? this.stopReason;
|
|
142
|
+
// Close the write stream
|
|
143
|
+
if (this.writeStream) {
|
|
144
|
+
await new Promise((resolve, reject) => {
|
|
145
|
+
this.writeStream.end((err) => {
|
|
146
|
+
if (err)
|
|
147
|
+
reject(err);
|
|
148
|
+
else
|
|
149
|
+
resolve();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
let saved = false;
|
|
154
|
+
let finalPath = this.tempPath;
|
|
155
|
+
// Determine whether to save based on mode and exit code
|
|
156
|
+
const shouldSave = this.mode === 'always' ||
|
|
157
|
+
(this.mode === 'on-failure' && exitCode !== 0 && exitCode !== null);
|
|
158
|
+
if (shouldSave) {
|
|
159
|
+
// Check if temp file exists before attempting to save
|
|
160
|
+
if (!fs.existsSync(this.tempPath)) {
|
|
161
|
+
// Temp file doesn't exist - recording may not have started properly or was cleaned up
|
|
162
|
+
return {
|
|
163
|
+
id: this.id,
|
|
164
|
+
path: '',
|
|
165
|
+
tempPath: this.tempPath,
|
|
166
|
+
startTime: this.startTime,
|
|
167
|
+
endTime,
|
|
168
|
+
durationMs,
|
|
169
|
+
bytesWritten: this.bytesWritten,
|
|
170
|
+
exitCode,
|
|
171
|
+
mode: this.mode,
|
|
172
|
+
saved: false,
|
|
173
|
+
stopReason: finalStopReason,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// Ensure output directory exists (defensive check for cases where dir was deleted during recording)
|
|
177
|
+
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
178
|
+
// Move temp file to final location
|
|
179
|
+
try {
|
|
180
|
+
fs.renameSync(this.tempPath, this.finalPath);
|
|
181
|
+
finalPath = this.finalPath;
|
|
182
|
+
saved = true;
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
// If rename fails (cross-device), try copy and delete
|
|
186
|
+
try {
|
|
187
|
+
fs.copyFileSync(this.tempPath, this.finalPath);
|
|
188
|
+
fs.unlinkSync(this.tempPath);
|
|
189
|
+
finalPath = this.finalPath;
|
|
190
|
+
saved = true;
|
|
191
|
+
}
|
|
192
|
+
catch (copyErr) {
|
|
193
|
+
// Both rename and copy failed - temp file may have been deleted
|
|
194
|
+
console.error('[recorder] Failed to save recording:', copyErr);
|
|
195
|
+
// Return with saved=false
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Write metadata sidecar file only if recording was saved
|
|
199
|
+
if (saved) {
|
|
200
|
+
const metaPath = this.finalPath.replace(/\.cast$/, '.meta.json');
|
|
201
|
+
const meta = {
|
|
202
|
+
exitCode,
|
|
203
|
+
durationMs,
|
|
204
|
+
startTime: this.startTime,
|
|
205
|
+
endTime,
|
|
206
|
+
bytesWritten: this.bytesWritten,
|
|
207
|
+
stopReason: finalStopReason,
|
|
208
|
+
};
|
|
209
|
+
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// Delete temp file
|
|
214
|
+
try {
|
|
215
|
+
fs.unlinkSync(this.tempPath);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Ignore if already deleted
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
id: this.id,
|
|
223
|
+
path: saved ? finalPath : '',
|
|
224
|
+
tempPath: this.tempPath,
|
|
225
|
+
startTime: this.startTime,
|
|
226
|
+
endTime,
|
|
227
|
+
durationMs,
|
|
228
|
+
bytesWritten: this.bytesWritten,
|
|
229
|
+
exitCode,
|
|
230
|
+
mode: this.mode,
|
|
231
|
+
saved,
|
|
232
|
+
stopReason: finalStopReason,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Check if recording is active
|
|
237
|
+
*/
|
|
238
|
+
isActive() {
|
|
239
|
+
return this.writeStream !== null && !this.finalized;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Get the temp file path (for debugging/testing)
|
|
243
|
+
*/
|
|
244
|
+
getTempPath() {
|
|
245
|
+
return this.tempPath;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get the final file path
|
|
249
|
+
*/
|
|
250
|
+
getFinalPath() {
|
|
251
|
+
return this.finalPath;
|
|
252
|
+
}
|
|
253
|
+
getElapsedSeconds() {
|
|
254
|
+
const now = Date.now();
|
|
255
|
+
if (this.lastEventTime === 0) {
|
|
256
|
+
// First event - just record the time
|
|
257
|
+
this.lastEventTime = now;
|
|
258
|
+
this.adjustedElapsed = (now - this.startTime) / 1000;
|
|
259
|
+
return this.adjustedElapsed;
|
|
260
|
+
}
|
|
261
|
+
// Calculate actual idle time since last event
|
|
262
|
+
const idleTime = (now - this.lastEventTime) / 1000;
|
|
263
|
+
// Cap idle time if limit is set and exceeded
|
|
264
|
+
if (this.idleTimeLimit > 0 && idleTime > this.idleTimeLimit) {
|
|
265
|
+
// Only add the capped idle time to our adjusted elapsed
|
|
266
|
+
this.adjustedElapsed += this.idleTimeLimit;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Add actual idle time
|
|
270
|
+
this.adjustedElapsed += idleTime;
|
|
271
|
+
}
|
|
272
|
+
this.lastEventTime = now;
|
|
273
|
+
return this.adjustedElapsed;
|
|
274
|
+
}
|
|
275
|
+
writeLine(line) {
|
|
276
|
+
if (this.writeStream) {
|
|
277
|
+
const data = line + '\n';
|
|
278
|
+
this.writeStream.write(data);
|
|
279
|
+
this.bytesWritten += Buffer.byteLength(data, 'utf8');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Clear all active timers
|
|
284
|
+
*/
|
|
285
|
+
clearTimers() {
|
|
286
|
+
if (this.maxDurationTimer) {
|
|
287
|
+
clearTimeout(this.maxDurationTimer);
|
|
288
|
+
this.maxDurationTimer = null;
|
|
289
|
+
}
|
|
290
|
+
if (this.inactivityTimer) {
|
|
291
|
+
clearTimeout(this.inactivityTimer);
|
|
292
|
+
this.inactivityTimer = null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Auto-finalize the recording due to timeout
|
|
297
|
+
* Called internally when max duration or inactivity timeout is reached
|
|
298
|
+
*/
|
|
299
|
+
async _autoFinalize(reason) {
|
|
300
|
+
if (this.finalized) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.stopReason = reason;
|
|
304
|
+
const metadata = await this.finalize(null, reason);
|
|
305
|
+
// Notify callback if registered
|
|
306
|
+
if (this.onAutoFinalize) {
|
|
307
|
+
this.onAutoFinalize(metadata);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Set callback for auto-finalize events (timeout triggered)
|
|
312
|
+
*/
|
|
313
|
+
setOnAutoFinalize(callback) {
|
|
314
|
+
this.onAutoFinalize = callback;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get timeout configuration and remaining time
|
|
318
|
+
*/
|
|
319
|
+
getTimeoutInfo() {
|
|
320
|
+
const elapsedSeconds = this.startTime > 0 ? (Date.now() - this.startTime) / 1000 : 0;
|
|
321
|
+
const remainingMaxDuration = this.maxDuration > 0 ? Math.max(0, this.maxDuration - elapsedSeconds) : -1;
|
|
322
|
+
return {
|
|
323
|
+
maxDuration: this.maxDuration,
|
|
324
|
+
inactivityTimeout: this.inactivityTimeout,
|
|
325
|
+
elapsedSeconds,
|
|
326
|
+
remainingMaxDuration,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/recording/recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recording mode determines when recordings are saved
|
|
3
|
+
* - 'always': Save all recordings
|
|
4
|
+
* - 'on-failure': Only save recordings when the session exits with non-zero code
|
|
5
|
+
* - 'off': Disable recording
|
|
6
|
+
*/
|
|
7
|
+
export type RecordingMode = 'always' | 'on-failure' | 'off';
|
|
8
|
+
/**
|
|
9
|
+
* Recording format (asciicast v2 is the only supported format)
|
|
10
|
+
*/
|
|
11
|
+
export type RecordingFormat = 'v2';
|
|
12
|
+
/**
|
|
13
|
+
* Options for creating a recording
|
|
14
|
+
*/
|
|
15
|
+
export interface RecordingOptions {
|
|
16
|
+
mode: RecordingMode;
|
|
17
|
+
format: RecordingFormat;
|
|
18
|
+
outputDir: string;
|
|
19
|
+
idleTimeLimit?: number;
|
|
20
|
+
maxDuration?: number;
|
|
21
|
+
inactivityTimeout?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Asciicast v2 header (first line of the .cast file)
|
|
25
|
+
*/
|
|
26
|
+
export interface AsciicastHeader {
|
|
27
|
+
version: 2;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
timestamp: number;
|
|
31
|
+
env?: {
|
|
32
|
+
SHELL?: string;
|
|
33
|
+
TERM?: string;
|
|
34
|
+
};
|
|
35
|
+
title?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Asciicast event types:
|
|
39
|
+
* - 'o': output (data written to terminal)
|
|
40
|
+
* - 'r': resize (terminal dimensions changed)
|
|
41
|
+
*/
|
|
42
|
+
export type AsciicastOutputEvent = [number, 'o', string];
|
|
43
|
+
export type AsciicastResizeEvent = [number, 'r', string];
|
|
44
|
+
export type AsciicastEvent = AsciicastOutputEvent | AsciicastResizeEvent;
|
|
45
|
+
/**
|
|
46
|
+
* Reason why recording stopped
|
|
47
|
+
*/
|
|
48
|
+
export type StopReason = 'explicit' | 'session_exit' | 'max_duration' | 'inactivity';
|
|
49
|
+
/**
|
|
50
|
+
* Metadata returned after finalizing a recording
|
|
51
|
+
*/
|
|
52
|
+
export interface RecordingMetadata {
|
|
53
|
+
id: string;
|
|
54
|
+
path: string;
|
|
55
|
+
tempPath: string;
|
|
56
|
+
startTime: number;
|
|
57
|
+
endTime: number;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
bytesWritten: number;
|
|
60
|
+
exitCode: number | null;
|
|
61
|
+
mode: RecordingMode;
|
|
62
|
+
saved: boolean;
|
|
63
|
+
stopReason?: StopReason;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/recording/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,KAAK,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC;AAEnC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE;QACJ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/recording/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModeSelector.d.ts","sourceRoot":"","sources":["../../src/sandbox/ModeSelector.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModeSelector.js","sourceRoot":"","sources":["../../src/sandbox/ModeSelector.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox filesystem permission configuration
|
|
3
|
+
*/
|
|
4
|
+
export interface FilesystemPermissions {
|
|
5
|
+
/** Paths with full read/write access */
|
|
6
|
+
readWrite: string[];
|
|
7
|
+
/** Paths with read-only access */
|
|
8
|
+
readOnly: string[];
|
|
9
|
+
/** Paths completely blocked from access */
|
|
10
|
+
blocked: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Sandbox network permission configuration
|
|
14
|
+
*/
|
|
15
|
+
export interface NetworkPermissions {
|
|
16
|
+
/** Network access mode */
|
|
17
|
+
mode: "all" | "none" | "allowlist";
|
|
18
|
+
/** Allowed domains when mode is 'allowlist' */
|
|
19
|
+
allowedDomains?: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Full sandbox permissions configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface SandboxPermissions {
|
|
25
|
+
filesystem: FilesystemPermissions;
|
|
26
|
+
network: NetworkPermissions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Default permissions for sandbox mode
|
|
30
|
+
* Provides reasonable defaults while blocking sensitive directories
|
|
31
|
+
* Allows shell-related files to be writable for normal shell operation
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_PERMISSIONS: SandboxPermissions;
|
|
34
|
+
/**
|
|
35
|
+
* Expand ~ to home directory in a path
|
|
36
|
+
*/
|
|
37
|
+
export declare function expandPath(p: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Load sandbox configuration from a JSON file
|
|
40
|
+
*/
|
|
41
|
+
export declare function loadConfigFromFile(filePath: string): SandboxPermissions;
|
|
42
|
+
/**
|
|
43
|
+
* Merge user selections with defaults
|
|
44
|
+
*/
|
|
45
|
+
export declare function mergePermissions(base: SandboxPermissions, overrides: Partial<SandboxPermissions>): SandboxPermissions;
|
|
46
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/sandbox/config.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC;IACnC,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,qBAAqB,CAAC;IAClC,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBA+CjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW5C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAiBvE;AA+DD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACrC,kBAAkB,CAYpB"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Default permissions for sandbox mode
|
|
6
|
+
* Provides reasonable defaults while blocking sensitive directories
|
|
7
|
+
* Allows shell-related files to be writable for normal shell operation
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_PERMISSIONS = {
|
|
10
|
+
filesystem: {
|
|
11
|
+
readWrite: [
|
|
12
|
+
// Core paths
|
|
13
|
+
".", // Current working directory
|
|
14
|
+
"/tmp", // Temp files
|
|
15
|
+
// Shell operation
|
|
16
|
+
"~/.cache", // Cache files (oh-my-zsh, etc.)
|
|
17
|
+
"~/.local", // Local user data
|
|
18
|
+
"~/.zsh_history", // Zsh history
|
|
19
|
+
"~/.bash_history", // Bash history
|
|
20
|
+
"~/.node_repl_history", // Node REPL history
|
|
21
|
+
"~/.python_history", // Python history
|
|
22
|
+
// Package managers
|
|
23
|
+
"~/.npm",
|
|
24
|
+
"~/.yarn",
|
|
25
|
+
"~/.pnpm",
|
|
26
|
+
"~/.bun",
|
|
27
|
+
],
|
|
28
|
+
readOnly: [
|
|
29
|
+
"~", // Home directory (general read access)
|
|
30
|
+
],
|
|
31
|
+
blocked: [
|
|
32
|
+
// SSH/GPG
|
|
33
|
+
"~/.ssh",
|
|
34
|
+
"~/.gnupg",
|
|
35
|
+
// Cloud credentials
|
|
36
|
+
"~/.aws",
|
|
37
|
+
"~/.config/gcloud",
|
|
38
|
+
"~/.azure",
|
|
39
|
+
"~/.kube",
|
|
40
|
+
// CLI credentials
|
|
41
|
+
"~/.config/gh",
|
|
42
|
+
// Auth tokens
|
|
43
|
+
"~/.npmrc",
|
|
44
|
+
"~/.netrc",
|
|
45
|
+
"~/.docker/config.json",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
network: {
|
|
49
|
+
mode: "all",
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Expand ~ to home directory in a path
|
|
54
|
+
*/
|
|
55
|
+
export function expandPath(p) {
|
|
56
|
+
if (p.startsWith("~/")) {
|
|
57
|
+
return path.join(os.homedir(), p.slice(2));
|
|
58
|
+
}
|
|
59
|
+
if (p === "~") {
|
|
60
|
+
return os.homedir();
|
|
61
|
+
}
|
|
62
|
+
if (p === ".") {
|
|
63
|
+
return process.cwd();
|
|
64
|
+
}
|
|
65
|
+
return path.resolve(p);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Load sandbox configuration from a JSON file
|
|
69
|
+
*/
|
|
70
|
+
export function loadConfigFromFile(filePath) {
|
|
71
|
+
const expandedPath = expandPath(filePath);
|
|
72
|
+
if (!fs.existsSync(expandedPath)) {
|
|
73
|
+
throw new Error(`Sandbox config file not found: ${expandedPath}`);
|
|
74
|
+
}
|
|
75
|
+
const content = fs.readFileSync(expandedPath, "utf-8");
|
|
76
|
+
let config;
|
|
77
|
+
try {
|
|
78
|
+
config = JSON.parse(content);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
throw new Error(`Invalid JSON in sandbox config file: ${expandedPath}`);
|
|
82
|
+
}
|
|
83
|
+
return validateConfig(config);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validate and normalize a config object
|
|
87
|
+
*/
|
|
88
|
+
function validateConfig(config) {
|
|
89
|
+
if (typeof config !== "object" || config === null) {
|
|
90
|
+
throw new Error("Sandbox config must be an object");
|
|
91
|
+
}
|
|
92
|
+
const obj = config;
|
|
93
|
+
const result = {
|
|
94
|
+
filesystem: {
|
|
95
|
+
readWrite: [],
|
|
96
|
+
readOnly: [],
|
|
97
|
+
blocked: [],
|
|
98
|
+
},
|
|
99
|
+
network: {
|
|
100
|
+
mode: "all",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
// Validate filesystem config
|
|
104
|
+
if (obj.filesystem && typeof obj.filesystem === "object") {
|
|
105
|
+
const fs = obj.filesystem;
|
|
106
|
+
if (Array.isArray(fs.readWrite)) {
|
|
107
|
+
result.filesystem.readWrite = fs.readWrite.filter((p) => typeof p === "string");
|
|
108
|
+
}
|
|
109
|
+
if (Array.isArray(fs.readOnly)) {
|
|
110
|
+
result.filesystem.readOnly = fs.readOnly.filter((p) => typeof p === "string");
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(fs.blocked)) {
|
|
113
|
+
result.filesystem.blocked = fs.blocked.filter((p) => typeof p === "string");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Validate network config
|
|
117
|
+
if (obj.network && typeof obj.network === "object") {
|
|
118
|
+
const net = obj.network;
|
|
119
|
+
if (net.mode === "all" || net.mode === "none" || net.mode === "allowlist") {
|
|
120
|
+
result.network.mode = net.mode;
|
|
121
|
+
}
|
|
122
|
+
if (Array.isArray(net.allowedDomains)) {
|
|
123
|
+
result.network.allowedDomains = net.allowedDomains.filter((d) => typeof d === "string");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Merge user selections with defaults
|
|
130
|
+
*/
|
|
131
|
+
export function mergePermissions(base, overrides) {
|
|
132
|
+
return {
|
|
133
|
+
filesystem: {
|
|
134
|
+
readWrite: overrides.filesystem?.readWrite ?? base.filesystem.readWrite,
|
|
135
|
+
readOnly: overrides.filesystem?.readOnly ?? base.filesystem.readOnly,
|
|
136
|
+
blocked: overrides.filesystem?.blocked ?? base.filesystem.blocked,
|
|
137
|
+
},
|
|
138
|
+
network: {
|
|
139
|
+
mode: overrides.network?.mode ?? base.network.mode,
|
|
140
|
+
allowedDomains: overrides.network?.allowedDomains ?? base.network.allowedDomains,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/sandbox/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAgC7B;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuB;IACrD,UAAU,EAAE;QACV,SAAS,EAAE;YACT,aAAa;YACb,GAAG,EAAe,4BAA4B;YAC9C,MAAM,EAAY,aAAa;YAE/B,kBAAkB;YAClB,UAAU,EAAQ,gCAAgC;YAClD,UAAU,EAAQ,kBAAkB;YACpC,gBAAgB,EAAE,cAAc;YAChC,iBAAiB,EAAE,eAAe;YAClC,sBAAsB,EAAE,oBAAoB;YAC5C,mBAAmB,EAAE,iBAAiB;YAEtC,mBAAmB;YACnB,QAAQ;YACR,SAAS;YACT,SAAS;YACT,QAAQ;SACT;QACD,QAAQ,EAAE;YACR,GAAG,EAAe,uCAAuC;SAC1D;QACD,OAAO,EAAE;YACP,UAAU;YACV,QAAQ;YACR,UAAU;YAEV,oBAAoB;YACpB,QAAQ;YACR,kBAAkB;YAClB,UAAU;YACV,SAAS;YAET,kBAAkB;YAClB,cAAc;YAEd,cAAc;YACd,UAAU;YACV,UAAU;YACV,uBAAuB;SACxB;KACF;IACD,OAAO,EAAE;QACP,IAAI,EAAE,KAAK;KACZ;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QACd,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IACD,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QACd,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,kCAAkC,YAAY,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACvD,IAAI,MAAe,CAAC;IAEpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,wCAAwC,YAAY,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,MAAe;IACrC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,MAAM,GAAuB;QACjC,UAAU,EAAE;YACV,SAAS,EAAE,EAAE;YACb,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ;QACD,OAAO,EAAE;YACP,IAAI,EAAE,KAAK;SACZ;KACF,CAAC;IAEF,6BAA6B;IAC7B,IAAI,GAAG,CAAC,UAAU,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACzD,MAAM,EAAE,GAAG,GAAG,CAAC,UAAqC,CAAC;QAErD,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,UAAU,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAC7C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,UAAU,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,IAAI,GAAG,CAAC,OAAO,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAkC,CAAC;QAEnD,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1E,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACjC,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YACtC,MAAM,CAAC,OAAO,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC,MAAM,CACvD,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAwB,EACxB,SAAsC;IAEtC,OAAO;QACL,UAAU,EAAE;YACV,SAAS,EAAE,SAAS,CAAC,UAAU,EAAE,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS;YACvE,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ;YACpE,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO;SAClE;QACD,OAAO,EAAE;YACP,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI;YAClD,cAAc,EAAE,SAAS,CAAC,OAAO,EAAE,cAAc,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc;SACjF;KACF,CAAC;AACJ,CAAC"}
|