@timetotest/cli 0.2.4 → 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/README.md +49 -40
- package/dist/bin/ttt.js +0 -2
- package/dist/bin/ttt.js.map +1 -1
- package/dist/package.json +7 -3
- package/dist/src/commands/chat/ChatApp.js +249 -67
- package/dist/src/commands/chat/ChatApp.js.map +1 -1
- package/dist/src/commands/chat/components/ChatInput.js +61 -22
- package/dist/src/commands/chat/components/ChatInput.js.map +1 -1
- package/dist/src/commands/chat/components/ChatMessage.js +102 -0
- package/dist/src/commands/chat/components/ChatMessage.js.map +1 -0
- package/dist/src/commands/chat/components/MessageBubble.js +1 -1
- package/dist/src/commands/chat/components/MessageBubble.js.map +1 -1
- package/dist/src/commands/chat/components/PermissionPrompt.js +92 -0
- package/dist/src/commands/chat/components/PermissionPrompt.js.map +1 -0
- package/dist/src/commands/chat/components/StatusIndicator.js +21 -5
- package/dist/src/commands/chat/components/StatusIndicator.js.map +1 -1
- package/dist/src/commands/chat/components/ToolCallDisplay.js +141 -0
- package/dist/src/commands/chat/components/ToolCallDisplay.js.map +1 -0
- package/dist/src/commands/chat-ink.js +298 -79
- package/dist/src/commands/chat-ink.js.map +1 -1
- package/dist/src/commands/login.js +5 -5
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/test.js +14 -291
- package/dist/src/commands/test.js.map +1 -1
- package/dist/src/lib/__tests__/code-mode-integration.test.js +381 -0
- package/dist/src/lib/__tests__/code-mode-integration.test.js.map +1 -0
- package/dist/src/lib/__tests__/config-manager.test.js +81 -0
- package/dist/src/lib/__tests__/config-manager.test.js.map +1 -0
- package/dist/src/lib/__tests__/mode-persistence-integration.test.js +75 -0
- package/dist/src/lib/__tests__/mode-persistence-integration.test.js.map +1 -0
- package/dist/src/lib/__tests__/permission-flow-integration.test.js +145 -0
- package/dist/src/lib/__tests__/permission-flow-integration.test.js.map +1 -0
- package/dist/src/lib/__tests__/permissions.test.js +132 -0
- package/dist/src/lib/__tests__/permissions.test.js.map +1 -0
- package/dist/src/lib/agent-orchestrator.js +259 -5
- package/dist/src/lib/agent-orchestrator.js.map +1 -1
- package/dist/src/lib/config.js +40 -0
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/context-compactor.js +310 -0
- package/dist/src/lib/context-compactor.js.map +1 -0
- package/dist/src/lib/http.js +8 -0
- package/dist/src/lib/http.js.map +1 -1
- package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js +146 -0
- package/dist/src/lib/local-tools/code/__tests__/grep-search.test.js.map +1 -0
- package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js +192 -0
- package/dist/src/lib/local-tools/code/__tests__/list-directory.test.js.map +1 -0
- package/dist/src/lib/local-tools/code/__tests__/read-file.test.js +169 -0
- package/dist/src/lib/local-tools/code/__tests__/read-file.test.js.map +1 -0
- package/dist/src/lib/local-tools/code/__tests__/run-command.test.js +101 -0
- package/dist/src/lib/local-tools/code/__tests__/run-command.test.js.map +1 -0
- package/dist/src/lib/local-tools/code/__tests__/search-files.test.js +191 -0
- package/dist/src/lib/local-tools/code/__tests__/search-files.test.js.map +1 -0
- package/dist/src/lib/local-tools/code/grep-search.js +404 -0
- package/dist/src/lib/local-tools/code/grep-search.js.map +1 -0
- package/dist/src/lib/local-tools/code/index.js +11 -0
- package/dist/src/lib/local-tools/code/index.js.map +1 -0
- package/dist/src/lib/local-tools/code/list-directory.js +276 -0
- package/dist/src/lib/local-tools/code/list-directory.js.map +1 -0
- package/dist/src/lib/local-tools/code/read-file.js +301 -0
- package/dist/src/lib/local-tools/code/read-file.js.map +1 -0
- package/dist/src/lib/local-tools/code/run-command.js +235 -0
- package/dist/src/lib/local-tools/code/run-command.js.map +1 -0
- package/dist/src/lib/local-tools/code/search-files.js +297 -0
- package/dist/src/lib/local-tools/code/search-files.js.map +1 -0
- package/dist/src/lib/local-tools/code/types.js +6 -0
- package/dist/src/lib/local-tools/code/types.js.map +1 -0
- package/dist/src/lib/permissions.js +94 -0
- package/dist/src/lib/permissions.js.map +1 -0
- package/dist/src/lib/prompts/builder.js +13 -10
- package/dist/src/lib/prompts/builder.js.map +1 -1
- package/dist/src/lib/prompts/templates.js +78 -0
- package/dist/src/lib/prompts/templates.js.map +1 -1
- package/dist/src/lib/session-manager.js.map +1 -1
- package/dist/src/lib/testing-mode.js +2 -2
- package/dist/src/lib/testing-mode.js.map +1 -1
- package/dist/src/lib/tool-executor.js +131 -2
- package/dist/src/lib/tool-executor.js.map +1 -1
- package/dist/src/lib/tool-registry.js +171 -3
- package/dist/src/lib/tool-registry.js.map +1 -1
- package/dist/src/lib/tool-result-pruner.js +4 -4
- package/dist/src/lib/tool-result-pruner.js.map +1 -1
- package/dist/src/lib/tui/ink/components/AppFrame.js +17 -0
- package/dist/src/lib/tui/ink/components/AppFrame.js.map +1 -0
- package/dist/src/lib/tui/ink/components/CommandPalette.js +24 -0
- package/dist/src/lib/tui/ink/components/CommandPalette.js.map +1 -0
- package/dist/src/lib/tui/ink/components/Pill.js +19 -0
- package/dist/src/lib/tui/ink/components/Pill.js.map +1 -0
- package/dist/src/lib/tui/ink/components/TimetoTestLogo.js +30 -0
- package/dist/src/lib/tui/ink/components/TimetoTestLogo.js.map +1 -0
- package/dist/src/lib/tui/ink/theme.js +13 -6
- package/dist/src/lib/tui/ink/theme.js.map +1 -1
- package/dist/src/lib/tui/interactive-chat.js +35 -35
- package/dist/src/lib/tui/interactive-chat.js.map +1 -1
- package/dist/src/lib/tui/print.js +18 -18
- package/dist/src/lib/tui/print.js.map +1 -1
- package/dist/src/lib/tui/prompt.js +3 -3
- package/dist/src/lib/tui/prompt.js.map +1 -1
- package/dist/src/lib/tui/status.js +1 -1
- package/dist/src/lib/tui/status.js.map +1 -1
- package/dist/src/lib/update.js +10 -10
- package/dist/src/lib/update.js.map +1 -1
- package/package.json +7 -3
- package/dist/src/commands/start-test.js +0 -180
- package/dist/src/commands/start-test.js.map +0 -1
- package/dist/src/commands/stream/StreamApp.js +0 -127
- package/dist/src/commands/stream/StreamApp.js.map +0 -1
- package/dist/src/commands/stream.js +0 -52
- package/dist/src/commands/stream.js.map +0 -1
- package/dist/src/commands/test/TestRunApp.js +0 -183
- package/dist/src/commands/test/TestRunApp.js.map +0 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_directory tool - List directory contents with filtering options.
|
|
3
|
+
* Supports glob pattern filtering, recursive listing, and hidden file filtering.
|
|
4
|
+
*
|
|
5
|
+
* Security: Implements path validation to prevent directory traversal (TR-5).
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "fs/promises";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
// Default max depth for recursive listing to prevent excessive traversal
|
|
10
|
+
const DEFAULT_MAX_DEPTH = 10;
|
|
11
|
+
// Maximum number of entries to return to prevent memory issues
|
|
12
|
+
const MAX_ENTRIES = 1000;
|
|
13
|
+
/**
|
|
14
|
+
* Validate and resolve a directory path to prevent directory traversal.
|
|
15
|
+
* Returns the resolved absolute path if valid, or an error.
|
|
16
|
+
*
|
|
17
|
+
* Security (TR-5):
|
|
18
|
+
* - All paths normalized and validated against project root
|
|
19
|
+
* - Reject paths containing `..` that escape root
|
|
20
|
+
* - Use `path.resolve()` and check prefix
|
|
21
|
+
*/
|
|
22
|
+
function validatePath(dirPath, workingDirectory) {
|
|
23
|
+
// Normalize the working directory to absolute path
|
|
24
|
+
const rootDir = path.resolve(workingDirectory);
|
|
25
|
+
// Resolve the requested path relative to working directory
|
|
26
|
+
const resolvedPath = path.resolve(rootDir, dirPath);
|
|
27
|
+
// Security check: ensure resolved path is within root directory
|
|
28
|
+
// Use path.sep to ensure we're checking directory boundaries properly
|
|
29
|
+
const normalizedRoot = rootDir.endsWith(path.sep)
|
|
30
|
+
? rootDir
|
|
31
|
+
: rootDir + path.sep;
|
|
32
|
+
const normalizedResolved = resolvedPath + path.sep;
|
|
33
|
+
if (!normalizedResolved.startsWith(normalizedRoot) &&
|
|
34
|
+
resolvedPath !== rootDir) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
error: "Path validation failed: access denied",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return { valid: true, resolvedPath };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a filename matches a glob pattern.
|
|
44
|
+
* Supports basic glob patterns: *, ?, and character classes [abc].
|
|
45
|
+
*/
|
|
46
|
+
function matchesGlobPattern(filename, pattern) {
|
|
47
|
+
// Convert glob pattern to regex
|
|
48
|
+
let regexPattern = pattern
|
|
49
|
+
// Escape special regex characters except glob wildcards
|
|
50
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
51
|
+
// Convert glob * to regex .*
|
|
52
|
+
.replace(/\*/g, ".*")
|
|
53
|
+
// Convert glob ? to regex .
|
|
54
|
+
.replace(/\?/g, ".");
|
|
55
|
+
// Create regex with case-insensitive matching for cross-platform compatibility
|
|
56
|
+
const regex = new RegExp(`^${regexPattern}$`, "i");
|
|
57
|
+
return regex.test(filename);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if a file/directory name is hidden (starts with .).
|
|
61
|
+
*/
|
|
62
|
+
function isHidden(name) {
|
|
63
|
+
return name.startsWith(".");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get file/directory stats and create a DirectoryEntry.
|
|
67
|
+
*/
|
|
68
|
+
async function createDirectoryEntry(entryPath, name) {
|
|
69
|
+
try {
|
|
70
|
+
const stats = await fs.stat(entryPath);
|
|
71
|
+
const entry = {
|
|
72
|
+
name,
|
|
73
|
+
type: stats.isDirectory() ? "directory" : "file",
|
|
74
|
+
};
|
|
75
|
+
// Add size for files
|
|
76
|
+
if (!stats.isDirectory()) {
|
|
77
|
+
entry.size = stats.size;
|
|
78
|
+
}
|
|
79
|
+
// Add modification time
|
|
80
|
+
entry.modified = stats.mtime.toISOString();
|
|
81
|
+
return entry;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Skip entries we can't stat (permission issues, etc.)
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Recursively list directory contents.
|
|
90
|
+
*/
|
|
91
|
+
async function listDirectoryRecursive(dirPath, rootDir, options) {
|
|
92
|
+
// Check depth limit
|
|
93
|
+
if (options.currentDepth > options.maxDepth) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Check entry limit
|
|
97
|
+
if (options.entries.length >= MAX_ENTRIES) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const items = await fs.readdir(dirPath);
|
|
102
|
+
for (const item of items) {
|
|
103
|
+
// Check entry limit
|
|
104
|
+
if (options.entries.length >= MAX_ENTRIES) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Skip hidden files if not included
|
|
108
|
+
if (!options.includeHidden && isHidden(item)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const fullPath = path.join(dirPath, item);
|
|
112
|
+
// Calculate relative path from base for display
|
|
113
|
+
const relativePath = options.basePath === "."
|
|
114
|
+
? item
|
|
115
|
+
: path.join(path.relative(path.resolve(rootDir, options.basePath), dirPath), item);
|
|
116
|
+
// Apply pattern filter if specified
|
|
117
|
+
if (options.pattern && !matchesGlobPattern(item, options.pattern)) {
|
|
118
|
+
// For directories, still recurse even if name doesn't match pattern
|
|
119
|
+
// (files inside might match)
|
|
120
|
+
try {
|
|
121
|
+
const stats = await fs.stat(fullPath);
|
|
122
|
+
if (stats.isDirectory()) {
|
|
123
|
+
await listDirectoryRecursive(fullPath, rootDir, {
|
|
124
|
+
...options,
|
|
125
|
+
currentDepth: options.currentDepth + 1,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Skip on error
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const entry = await createDirectoryEntry(fullPath, relativePath);
|
|
135
|
+
if (entry) {
|
|
136
|
+
options.entries.push(entry);
|
|
137
|
+
// Recurse into directories
|
|
138
|
+
if (entry.type === "directory") {
|
|
139
|
+
await listDirectoryRecursive(fullPath, rootDir, {
|
|
140
|
+
...options,
|
|
141
|
+
currentDepth: options.currentDepth + 1,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Skip directories we can't read
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* List directory contents with filtering options.
|
|
153
|
+
*
|
|
154
|
+
* @param args - ListDirectoryArgs containing path and filtering options
|
|
155
|
+
* @param context - CodeContext with working directory
|
|
156
|
+
* @returns ListDirectoryResult with directory entries
|
|
157
|
+
*/
|
|
158
|
+
export async function listDirectory(args, context) {
|
|
159
|
+
const { path: dirPath = ".", pattern, recursive = false, include_hidden = false, max_depth, } = args;
|
|
160
|
+
// Validate path to prevent directory traversal
|
|
161
|
+
const pathValidation = validatePath(dirPath, context.workingDirectory);
|
|
162
|
+
if (!pathValidation.valid) {
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
path: dirPath,
|
|
166
|
+
entries: [],
|
|
167
|
+
total_count: 0,
|
|
168
|
+
error: pathValidation.error,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const resolvedPath = pathValidation.resolvedPath;
|
|
172
|
+
try {
|
|
173
|
+
// Check if path exists and is a directory
|
|
174
|
+
const stats = await fs.stat(resolvedPath);
|
|
175
|
+
if (!stats.isDirectory()) {
|
|
176
|
+
return {
|
|
177
|
+
success: false,
|
|
178
|
+
path: dirPath,
|
|
179
|
+
entries: [],
|
|
180
|
+
total_count: 0,
|
|
181
|
+
error: "Path is not a directory",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const entries = [];
|
|
185
|
+
if (recursive) {
|
|
186
|
+
// Recursive listing
|
|
187
|
+
const effectiveMaxDepth = max_depth ?? DEFAULT_MAX_DEPTH;
|
|
188
|
+
await listDirectoryRecursive(resolvedPath, context.workingDirectory, {
|
|
189
|
+
pattern,
|
|
190
|
+
includeHidden: include_hidden,
|
|
191
|
+
maxDepth: effectiveMaxDepth,
|
|
192
|
+
currentDepth: 0,
|
|
193
|
+
entries,
|
|
194
|
+
basePath: dirPath,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Non-recursive listing
|
|
199
|
+
const items = await fs.readdir(resolvedPath);
|
|
200
|
+
for (const item of items) {
|
|
201
|
+
// Check entry limit
|
|
202
|
+
if (entries.length >= MAX_ENTRIES) {
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
// Skip hidden files if not included
|
|
206
|
+
if (!include_hidden && isHidden(item)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
// Apply pattern filter if specified
|
|
210
|
+
if (pattern && !matchesGlobPattern(item, pattern)) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const fullPath = path.join(resolvedPath, item);
|
|
214
|
+
const entry = await createDirectoryEntry(fullPath, item);
|
|
215
|
+
if (entry) {
|
|
216
|
+
entries.push(entry);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Sort entries: directories first, then alphabetically
|
|
221
|
+
entries.sort((a, b) => {
|
|
222
|
+
if (a.type !== b.type) {
|
|
223
|
+
return a.type === "directory" ? -1 : 1;
|
|
224
|
+
}
|
|
225
|
+
return a.name.localeCompare(b.name);
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
path: dirPath,
|
|
230
|
+
entries,
|
|
231
|
+
total_count: entries.length,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
// Handle specific error types without exposing sensitive info (TR-5)
|
|
236
|
+
if (error instanceof Error) {
|
|
237
|
+
const nodeError = error;
|
|
238
|
+
if (nodeError.code === "ENOENT") {
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
path: dirPath,
|
|
242
|
+
entries: [],
|
|
243
|
+
total_count: 0,
|
|
244
|
+
error: "Directory not found",
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (nodeError.code === "EACCES") {
|
|
248
|
+
return {
|
|
249
|
+
success: false,
|
|
250
|
+
path: dirPath,
|
|
251
|
+
entries: [],
|
|
252
|
+
total_count: 0,
|
|
253
|
+
error: "Permission denied",
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (nodeError.code === "ENOTDIR") {
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
path: dirPath,
|
|
260
|
+
entries: [],
|
|
261
|
+
total_count: 0,
|
|
262
|
+
error: "Path is not a directory",
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Generic error without exposing details (TR-5)
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
path: dirPath,
|
|
270
|
+
entries: [],
|
|
271
|
+
total_count: 0,
|
|
272
|
+
error: "Failed to list directory",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=list-directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-directory.js","sourceRoot":"","sources":["../../../../../src/lib/local-tools/code/list-directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* read_file tool - Read file contents with optional line range.
|
|
3
|
+
* Returns content with line numbers and language detection.
|
|
4
|
+
*
|
|
5
|
+
* Security: Implements path validation to prevent directory traversal (TR-5).
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "fs/promises";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
// Maximum file size to read (1MB default as per TR-5)
|
|
10
|
+
const MAX_FILE_SIZE = 1024 * 1024;
|
|
11
|
+
// Language detection map based on file extensions
|
|
12
|
+
const EXTENSION_TO_LANGUAGE = {
|
|
13
|
+
// JavaScript/TypeScript
|
|
14
|
+
".js": "javascript",
|
|
15
|
+
".jsx": "javascript",
|
|
16
|
+
".ts": "typescript",
|
|
17
|
+
".tsx": "typescript",
|
|
18
|
+
".mjs": "javascript",
|
|
19
|
+
".cjs": "javascript",
|
|
20
|
+
".mts": "typescript",
|
|
21
|
+
".cts": "typescript",
|
|
22
|
+
// Python
|
|
23
|
+
".py": "python",
|
|
24
|
+
".pyw": "python",
|
|
25
|
+
".pyi": "python",
|
|
26
|
+
// Web
|
|
27
|
+
".html": "html",
|
|
28
|
+
".htm": "html",
|
|
29
|
+
".css": "css",
|
|
30
|
+
".scss": "scss",
|
|
31
|
+
".sass": "sass",
|
|
32
|
+
".less": "less",
|
|
33
|
+
// Data formats
|
|
34
|
+
".json": "json",
|
|
35
|
+
".yaml": "yaml",
|
|
36
|
+
".yml": "yaml",
|
|
37
|
+
".xml": "xml",
|
|
38
|
+
".toml": "toml",
|
|
39
|
+
// Shell
|
|
40
|
+
".sh": "bash",
|
|
41
|
+
".bash": "bash",
|
|
42
|
+
".zsh": "zsh",
|
|
43
|
+
".fish": "fish",
|
|
44
|
+
".ps1": "powershell",
|
|
45
|
+
".bat": "batch",
|
|
46
|
+
".cmd": "batch",
|
|
47
|
+
// Other languages
|
|
48
|
+
".go": "go",
|
|
49
|
+
".rs": "rust",
|
|
50
|
+
".rb": "ruby",
|
|
51
|
+
".php": "php",
|
|
52
|
+
".java": "java",
|
|
53
|
+
".kt": "kotlin",
|
|
54
|
+
".kts": "kotlin",
|
|
55
|
+
".scala": "scala",
|
|
56
|
+
".c": "c",
|
|
57
|
+
".h": "c",
|
|
58
|
+
".cpp": "cpp",
|
|
59
|
+
".hpp": "cpp",
|
|
60
|
+
".cc": "cpp",
|
|
61
|
+
".cxx": "cpp",
|
|
62
|
+
".cs": "csharp",
|
|
63
|
+
".swift": "swift",
|
|
64
|
+
".r": "r",
|
|
65
|
+
".R": "r",
|
|
66
|
+
".lua": "lua",
|
|
67
|
+
".pl": "perl",
|
|
68
|
+
".pm": "perl",
|
|
69
|
+
".ex": "elixir",
|
|
70
|
+
".exs": "elixir",
|
|
71
|
+
".erl": "erlang",
|
|
72
|
+
".hrl": "erlang",
|
|
73
|
+
".clj": "clojure",
|
|
74
|
+
".cljs": "clojure",
|
|
75
|
+
".hs": "haskell",
|
|
76
|
+
".ml": "ocaml",
|
|
77
|
+
".mli": "ocaml",
|
|
78
|
+
".fs": "fsharp",
|
|
79
|
+
".fsx": "fsharp",
|
|
80
|
+
".dart": "dart",
|
|
81
|
+
".vue": "vue",
|
|
82
|
+
".svelte": "svelte",
|
|
83
|
+
// Config/Docs
|
|
84
|
+
".md": "markdown",
|
|
85
|
+
".mdx": "markdown",
|
|
86
|
+
".rst": "restructuredtext",
|
|
87
|
+
".txt": "text",
|
|
88
|
+
".ini": "ini",
|
|
89
|
+
".cfg": "ini",
|
|
90
|
+
".conf": "ini",
|
|
91
|
+
".env": "dotenv",
|
|
92
|
+
".gitignore": "gitignore",
|
|
93
|
+
".dockerignore": "dockerignore",
|
|
94
|
+
".editorconfig": "editorconfig",
|
|
95
|
+
// SQL
|
|
96
|
+
".sql": "sql",
|
|
97
|
+
// GraphQL
|
|
98
|
+
".graphql": "graphql",
|
|
99
|
+
".gql": "graphql",
|
|
100
|
+
// Makefile
|
|
101
|
+
Makefile: "makefile",
|
|
102
|
+
makefile: "makefile",
|
|
103
|
+
// Dockerfile
|
|
104
|
+
Dockerfile: "dockerfile",
|
|
105
|
+
dockerfile: "dockerfile",
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Detect language from file extension.
|
|
109
|
+
*/
|
|
110
|
+
function detectLanguage(filePath) {
|
|
111
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
112
|
+
const basename = path.basename(filePath);
|
|
113
|
+
// Check for special filenames first (Makefile, Dockerfile)
|
|
114
|
+
if (EXTENSION_TO_LANGUAGE[basename]) {
|
|
115
|
+
return EXTENSION_TO_LANGUAGE[basename];
|
|
116
|
+
}
|
|
117
|
+
return EXTENSION_TO_LANGUAGE[ext];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Validate and resolve a file path to prevent directory traversal.
|
|
121
|
+
* Returns the resolved absolute path if valid, or throws an error.
|
|
122
|
+
*
|
|
123
|
+
* Security (TR-5):
|
|
124
|
+
* - All paths normalized and validated against project root
|
|
125
|
+
* - Reject paths containing `..` that escape root
|
|
126
|
+
* - Use `path.resolve()` and check prefix
|
|
127
|
+
*/
|
|
128
|
+
function validatePath(filePath, workingDirectory) {
|
|
129
|
+
// Normalize the working directory to absolute path
|
|
130
|
+
const rootDir = path.resolve(workingDirectory);
|
|
131
|
+
// Resolve the requested path relative to working directory
|
|
132
|
+
const resolvedPath = path.resolve(rootDir, filePath);
|
|
133
|
+
// Security check: ensure resolved path is within root directory
|
|
134
|
+
// Use path.sep to ensure we're checking directory boundaries properly
|
|
135
|
+
const normalizedRoot = rootDir.endsWith(path.sep)
|
|
136
|
+
? rootDir
|
|
137
|
+
: rootDir + path.sep;
|
|
138
|
+
const normalizedResolved = resolvedPath + path.sep;
|
|
139
|
+
if (!normalizedResolved.startsWith(normalizedRoot) &&
|
|
140
|
+
resolvedPath !== rootDir) {
|
|
141
|
+
return {
|
|
142
|
+
valid: false,
|
|
143
|
+
error: "Path validation failed: access denied",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { valid: true, resolvedPath };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Format content with line numbers.
|
|
150
|
+
*/
|
|
151
|
+
function formatWithLineNumbers(lines, startLine, showLineNumbers) {
|
|
152
|
+
if (!showLineNumbers) {
|
|
153
|
+
return lines.join("\n");
|
|
154
|
+
}
|
|
155
|
+
const endLine = startLine + lines.length - 1;
|
|
156
|
+
const maxLineNumWidth = String(endLine).length;
|
|
157
|
+
return lines
|
|
158
|
+
.map((line, index) => {
|
|
159
|
+
const lineNum = startLine + index;
|
|
160
|
+
const paddedLineNum = String(lineNum).padStart(maxLineNumWidth, " ");
|
|
161
|
+
return `${paddedLineNum} | ${line}`;
|
|
162
|
+
})
|
|
163
|
+
.join("\n");
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Read file contents with optional line range.
|
|
167
|
+
*
|
|
168
|
+
* @param args - ReadFileArgs containing path and optional line range
|
|
169
|
+
* @param context - CodeContext with working directory
|
|
170
|
+
* @returns ReadFileResult with file content and metadata
|
|
171
|
+
*/
|
|
172
|
+
export async function readFile(args, context) {
|
|
173
|
+
const { path: filePath, start_line, end_line, show_line_numbers = true } = args;
|
|
174
|
+
// Validate path to prevent directory traversal
|
|
175
|
+
const pathValidation = validatePath(filePath, context.workingDirectory);
|
|
176
|
+
if (!pathValidation.valid) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
path: filePath,
|
|
180
|
+
content: "",
|
|
181
|
+
total_lines: 0,
|
|
182
|
+
start_line: 0,
|
|
183
|
+
end_line: 0,
|
|
184
|
+
error: pathValidation.error,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const resolvedPath = pathValidation.resolvedPath;
|
|
188
|
+
try {
|
|
189
|
+
// Check if file exists and get stats
|
|
190
|
+
const stats = await fs.stat(resolvedPath);
|
|
191
|
+
// Ensure it's a file, not a directory
|
|
192
|
+
if (stats.isDirectory()) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
path: filePath,
|
|
196
|
+
content: "",
|
|
197
|
+
total_lines: 0,
|
|
198
|
+
start_line: 0,
|
|
199
|
+
end_line: 0,
|
|
200
|
+
error: "Path is a directory, not a file",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Check file size limit (TR-5: Max file size limit for reading - 1MB default)
|
|
204
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
205
|
+
return {
|
|
206
|
+
success: false,
|
|
207
|
+
path: filePath,
|
|
208
|
+
content: "",
|
|
209
|
+
total_lines: 0,
|
|
210
|
+
start_line: 0,
|
|
211
|
+
end_line: 0,
|
|
212
|
+
error: `File exceeds maximum size limit of ${MAX_FILE_SIZE / 1024 / 1024}MB`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
// Read file content
|
|
216
|
+
const content = await fs.readFile(resolvedPath, "utf-8");
|
|
217
|
+
const allLines = content.split("\n");
|
|
218
|
+
const totalLines = allLines.length;
|
|
219
|
+
// Detect language from extension
|
|
220
|
+
const language = detectLanguage(filePath);
|
|
221
|
+
// Calculate line range (1-indexed, inclusive)
|
|
222
|
+
let effectiveStartLine = start_line ?? 1;
|
|
223
|
+
let effectiveEndLine = end_line ?? totalLines;
|
|
224
|
+
// Validate and clamp line numbers
|
|
225
|
+
if (effectiveStartLine < 1) {
|
|
226
|
+
effectiveStartLine = 1;
|
|
227
|
+
}
|
|
228
|
+
if (effectiveEndLine > totalLines) {
|
|
229
|
+
effectiveEndLine = totalLines;
|
|
230
|
+
}
|
|
231
|
+
if (effectiveStartLine > totalLines) {
|
|
232
|
+
effectiveStartLine = totalLines;
|
|
233
|
+
}
|
|
234
|
+
if (effectiveEndLine < effectiveStartLine) {
|
|
235
|
+
effectiveEndLine = effectiveStartLine;
|
|
236
|
+
}
|
|
237
|
+
// Extract requested lines (convert to 0-indexed for array slice)
|
|
238
|
+
const selectedLines = allLines.slice(effectiveStartLine - 1, effectiveEndLine);
|
|
239
|
+
// Format content with optional line numbers
|
|
240
|
+
const formattedContent = formatWithLineNumbers(selectedLines, effectiveStartLine, show_line_numbers);
|
|
241
|
+
return {
|
|
242
|
+
success: true,
|
|
243
|
+
path: filePath,
|
|
244
|
+
content: formattedContent,
|
|
245
|
+
total_lines: totalLines,
|
|
246
|
+
start_line: effectiveStartLine,
|
|
247
|
+
end_line: effectiveEndLine,
|
|
248
|
+
language,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
// Handle specific error types without exposing file contents (TR-5)
|
|
253
|
+
if (error instanceof Error) {
|
|
254
|
+
const nodeError = error;
|
|
255
|
+
if (nodeError.code === "ENOENT") {
|
|
256
|
+
return {
|
|
257
|
+
success: false,
|
|
258
|
+
path: filePath,
|
|
259
|
+
content: "",
|
|
260
|
+
total_lines: 0,
|
|
261
|
+
start_line: 0,
|
|
262
|
+
end_line: 0,
|
|
263
|
+
error: "File not found",
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
if (nodeError.code === "EACCES") {
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
path: filePath,
|
|
270
|
+
content: "",
|
|
271
|
+
total_lines: 0,
|
|
272
|
+
start_line: 0,
|
|
273
|
+
end_line: 0,
|
|
274
|
+
error: "Permission denied",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
if (nodeError.code === "EISDIR") {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
path: filePath,
|
|
281
|
+
content: "",
|
|
282
|
+
total_lines: 0,
|
|
283
|
+
start_line: 0,
|
|
284
|
+
end_line: 0,
|
|
285
|
+
error: "Path is a directory, not a file",
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Generic error without exposing details (TR-5: Never include file contents in error messages)
|
|
290
|
+
return {
|
|
291
|
+
success: false,
|
|
292
|
+
path: filePath,
|
|
293
|
+
content: "",
|
|
294
|
+
total_lines: 0,
|
|
295
|
+
start_line: 0,
|
|
296
|
+
end_line: 0,
|
|
297
|
+
error: "Failed to read file",
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=read-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-file.js","sourceRoot":"","sources":["../../../../../src/lib/local-tools/code/read-file.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,sDAAsD;AACtD,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,CAAC;AAElC,kDAAkD;AAClD,MAAM,qBAAqB,GAA2B;IACpD,wBAAwB;IACxB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,YAAY;IACnB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;IAEpB,SAAS;IACT,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAEhB,MAAM;IACN,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IAEf,eAAe;IACf,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,MAAM;IAEf,QAAQ;IACR,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,OAAO;IAEf,kBAAkB;IAClB,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,OAAO;IACjB,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,OAAO;IACjB,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,QAAQ;IAEnB,cAAc;IACd,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,kBAAkB;IAC1B,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,QAAQ;IAChB,YAAY,EAAE,WAAW;IACzB,eAAe,EAAE,cAAc;IAC/B,eAAe,EAAE,cAAc;IAE/B,MAAM;IACN,MAAM,EAAE,KAAK;IAEb,UAAU;IACV,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IAEjB,WAAW;IACX,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IAEpB,aAAa;IACb,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;CACzB,CAAC;AAEF;;GAEG;AACH,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEzC,2DAA2D;IAC3D,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,OAAO,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,qBAAqB,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CACnB,QAAgB,EAChB,gBAAwB;IAExB,mDAAmD;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE/C,2DAA2D;IAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAErD,gEAAgE;IAChE,sEAAsE;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/C,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC;IACvB,MAAM,kBAAkB,GAAG,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC;IAEnD,IACE,CAAC,kBAAkB,CAAC,UAAU,CAAC,cAAc,CAAC;QAC9C,YAAY,KAAK,OAAO,EACxB,CAAC;QACD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,uCAAuC;SAC/C,CAAC;IACJ,CAAC;IAED,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,KAAe,EACf,SAAiB,EACjB,eAAwB;IAExB,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7C,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAE/C,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC;QAClC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QACrE,OAAO,GAAG,aAAa,MAAM,IAAI,EAAE,CAAC;IACtC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAkB,EAClB,OAAoB;IAEpB,MAAM,EAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,EAAC,GAAG,IAAI,CAAC;IAE9E,+CAA+C;IAC/C,MAAM,cAAc,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC1B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,cAAc,CAAC,KAAK;SAC5B,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,cAAc,CAAC,YAAY,CAAC;IAEjD,IAAI,CAAC;QACH,qCAAqC;QACrC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAE1C,sCAAsC;QACtC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,CAAC;gBACd,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,iCAAiC;aACzC,CAAC;QACJ,CAAC;QAED,8EAA8E;QAC9E,IAAI,KAAK,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC;YAC/B,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,CAAC;gBACd,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,sCAAsC,aAAa,GAAG,IAAI,GAAG,IAAI,IAAI;aAC7E,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;QAEnC,iCAAiC;QACjC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAE1C,8CAA8C;QAC9C,IAAI,kBAAkB,GAAG,UAAU,IAAI,CAAC,CAAC;QACzC,IAAI,gBAAgB,GAAG,QAAQ,IAAI,UAAU,CAAC;QAE9C,kCAAkC;QAClC,IAAI,kBAAkB,GAAG,CAAC,EAAE,CAAC;YAC3B,kBAAkB,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,gBAAgB,GAAG,UAAU,EAAE,CAAC;YAClC,gBAAgB,GAAG,UAAU,CAAC;QAChC,CAAC;QACD,IAAI,kBAAkB,GAAG,UAAU,EAAE,CAAC;YACpC,kBAAkB,GAAG,UAAU,CAAC;QAClC,CAAC;QACD,IAAI,gBAAgB,GAAG,kBAAkB,EAAE,CAAC;YAC1C,gBAAgB,GAAG,kBAAkB,CAAC;QACxC,CAAC;QAED,iEAAiE;QACjE,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAClC,kBAAkB,GAAG,CAAC,EACtB,gBAAgB,CACjB,CAAC;QAEF,4CAA4C;QAC5C,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,aAAa,EACb,kBAAkB,EAClB,iBAAiB,CAClB,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,gBAAgB;YACzB,WAAW,EAAE,UAAU;YACvB,UAAU,EAAE,kBAAkB;YAC9B,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ;SACT,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,oEAAoE;QACpE,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,KAA8B,CAAC;YACjD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAChC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,CAAC;oBACd,UAAU,EAAE,CAAC;oBACb,QAAQ,EAAE,CAAC;oBACX,KAAK,EAAE,gBAAgB;iBACxB,CAAC;YACJ,CAAC;YACD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAChC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,CAAC;oBACd,UAAU,EAAE,CAAC;oBACb,QAAQ,EAAE,CAAC;oBACX,KAAK,EAAE,mBAAmB;iBAC3B,CAAC;YACJ,CAAC;YACD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAChC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,CAAC;oBACd,UAAU,EAAE,CAAC;oBACb,QAAQ,EAAE,CAAC;oBACX,KAAK,EAAE,iCAAiC;iBACzC,CAAC;YACJ,CAAC;QACH,CAAC;QAED,+FAA+F;QAC/F,OAAO;YACL,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,qBAAqB;SAC7B,CAAC;IACJ,CAAC;AACH,CAAC"}
|