@timetotest/cli 0.2.4 → 0.3.1
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 +8 -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/OnboardingApp.js +49 -0
- package/dist/src/commands/chat/OnboardingApp.js.map +1 -0
- package/dist/src/commands/chat/components/Banner.js +1 -1
- package/dist/src/commands/chat/components/Banner.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 +328 -93
- 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 +8 -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,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run_command tool - Execute shell commands with safety constraints.
|
|
3
|
+
* Supports timeout enforcement, working directory validation, and user permission prompts.
|
|
4
|
+
*
|
|
5
|
+
* Security (TR-5):
|
|
6
|
+
* - Working directory constrained to project root
|
|
7
|
+
* - Timeout enforced (default 30s)
|
|
8
|
+
* - No shell expansion (uses spawn, not exec)
|
|
9
|
+
* - User must approve command execution via permission prompt
|
|
10
|
+
*/
|
|
11
|
+
import { spawn } from "child_process";
|
|
12
|
+
import * as path from "path";
|
|
13
|
+
// Default timeout in milliseconds (30 seconds as per design)
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
15
|
+
// Maximum output size to capture (1MB per stream)
|
|
16
|
+
const MAX_OUTPUT_SIZE = 1024 * 1024;
|
|
17
|
+
/**
|
|
18
|
+
* Validate and resolve a working directory path to prevent directory traversal.
|
|
19
|
+
* Returns the resolved absolute path if valid, or an error.
|
|
20
|
+
*
|
|
21
|
+
* Security (TR-5):
|
|
22
|
+
* - All paths normalized and validated against project root
|
|
23
|
+
* - Reject paths containing `..` that escape root
|
|
24
|
+
* - Use `path.resolve()` and check prefix
|
|
25
|
+
*/
|
|
26
|
+
function validateWorkingDirectory(cwd, workingDirectory) {
|
|
27
|
+
// Normalize the root working directory to absolute path
|
|
28
|
+
const rootDir = path.resolve(workingDirectory);
|
|
29
|
+
// If no cwd specified, use the root directory
|
|
30
|
+
if (!cwd) {
|
|
31
|
+
return { valid: true, resolvedPath: rootDir };
|
|
32
|
+
}
|
|
33
|
+
// Resolve the requested path relative to working directory
|
|
34
|
+
const resolvedPath = path.resolve(rootDir, cwd);
|
|
35
|
+
// Security check: ensure resolved path is within root directory
|
|
36
|
+
// Use path.sep to ensure we're checking directory boundaries properly
|
|
37
|
+
const normalizedRoot = rootDir.endsWith(path.sep)
|
|
38
|
+
? rootDir
|
|
39
|
+
: rootDir + path.sep;
|
|
40
|
+
const normalizedResolved = resolvedPath + path.sep;
|
|
41
|
+
if (!normalizedResolved.startsWith(normalizedRoot) &&
|
|
42
|
+
resolvedPath !== rootDir) {
|
|
43
|
+
return {
|
|
44
|
+
valid: false,
|
|
45
|
+
error: "Working directory validation failed: access denied",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { valid: true, resolvedPath };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Truncate output if it exceeds the maximum size.
|
|
52
|
+
*
|
|
53
|
+
* @param output - The output string to potentially truncate
|
|
54
|
+
* @param maxSize - Maximum allowed size in bytes
|
|
55
|
+
* @returns Truncated output with indicator if truncated
|
|
56
|
+
*/
|
|
57
|
+
function truncateOutput(output, maxSize = MAX_OUTPUT_SIZE) {
|
|
58
|
+
if (Buffer.byteLength(output, "utf-8") <= maxSize) {
|
|
59
|
+
return output;
|
|
60
|
+
}
|
|
61
|
+
// Truncate to max size and add indicator
|
|
62
|
+
const truncated = Buffer.from(output, "utf-8")
|
|
63
|
+
.subarray(0, maxSize)
|
|
64
|
+
.toString("utf-8");
|
|
65
|
+
return truncated + "\n... [output truncated]";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Execute a command with timeout and capture output.
|
|
69
|
+
*
|
|
70
|
+
* @param command - The command to execute
|
|
71
|
+
* @param args - Command arguments
|
|
72
|
+
* @param cwd - Working directory
|
|
73
|
+
* @param timeout - Timeout in milliseconds
|
|
74
|
+
* @param env - Additional environment variables
|
|
75
|
+
* @returns Promise resolving to command result
|
|
76
|
+
*/
|
|
77
|
+
function executeCommand(command, args, cwd, timeout, env) {
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
const startTime = Date.now();
|
|
80
|
+
let stdout = "";
|
|
81
|
+
let stderr = "";
|
|
82
|
+
let timedOut = false;
|
|
83
|
+
let childProcess = null;
|
|
84
|
+
let timeoutId = null;
|
|
85
|
+
try {
|
|
86
|
+
// Spawn the process without shell to prevent shell expansion (TR-5)
|
|
87
|
+
childProcess = spawn(command, args, {
|
|
88
|
+
cwd,
|
|
89
|
+
env: { ...process.env, ...env },
|
|
90
|
+
// No shell to prevent command injection
|
|
91
|
+
shell: false,
|
|
92
|
+
// Detach to allow proper cleanup
|
|
93
|
+
detached: false,
|
|
94
|
+
// Set stdio to pipe for capturing output
|
|
95
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
96
|
+
});
|
|
97
|
+
// Set up timeout
|
|
98
|
+
timeoutId = setTimeout(() => {
|
|
99
|
+
timedOut = true;
|
|
100
|
+
if (childProcess && !childProcess.killed) {
|
|
101
|
+
// Kill the process and all its children
|
|
102
|
+
childProcess.kill("SIGTERM");
|
|
103
|
+
// Force kill after 5 seconds if still running
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
if (childProcess && !childProcess.killed) {
|
|
106
|
+
childProcess.kill("SIGKILL");
|
|
107
|
+
}
|
|
108
|
+
}, 5000);
|
|
109
|
+
}
|
|
110
|
+
}, timeout);
|
|
111
|
+
// Capture stdout with size limit
|
|
112
|
+
if (childProcess.stdout) {
|
|
113
|
+
childProcess.stdout.on("data", (data) => {
|
|
114
|
+
const chunk = data.toString("utf-8");
|
|
115
|
+
if (Buffer.byteLength(stdout, "utf-8") < MAX_OUTPUT_SIZE) {
|
|
116
|
+
stdout += chunk;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Capture stderr with size limit
|
|
121
|
+
if (childProcess.stderr) {
|
|
122
|
+
childProcess.stderr.on("data", (data) => {
|
|
123
|
+
const chunk = data.toString("utf-8");
|
|
124
|
+
if (Buffer.byteLength(stderr, "utf-8") < MAX_OUTPUT_SIZE) {
|
|
125
|
+
stderr += chunk;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Handle process completion
|
|
130
|
+
childProcess.on("close", (code) => {
|
|
131
|
+
if (timeoutId) {
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
}
|
|
134
|
+
const durationMs = Date.now() - startTime;
|
|
135
|
+
resolve({
|
|
136
|
+
exitCode: code ?? (timedOut ? 124 : 1), // 124 is conventional timeout exit code
|
|
137
|
+
stdout: truncateOutput(stdout),
|
|
138
|
+
stderr: truncateOutput(stderr),
|
|
139
|
+
timedOut,
|
|
140
|
+
durationMs,
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
// Handle spawn errors
|
|
144
|
+
childProcess.on("error", (error) => {
|
|
145
|
+
if (timeoutId) {
|
|
146
|
+
clearTimeout(timeoutId);
|
|
147
|
+
}
|
|
148
|
+
const durationMs = Date.now() - startTime;
|
|
149
|
+
resolve({
|
|
150
|
+
exitCode: 1,
|
|
151
|
+
stdout: truncateOutput(stdout),
|
|
152
|
+
stderr: truncateOutput(stderr + `\nSpawn error: ${error.message}`),
|
|
153
|
+
timedOut: false,
|
|
154
|
+
durationMs,
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (timeoutId) {
|
|
160
|
+
clearTimeout(timeoutId);
|
|
161
|
+
}
|
|
162
|
+
const durationMs = Date.now() - startTime;
|
|
163
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
164
|
+
resolve({
|
|
165
|
+
exitCode: 1,
|
|
166
|
+
stdout: "",
|
|
167
|
+
stderr: `Failed to spawn process: ${errorMessage}`,
|
|
168
|
+
timedOut: false,
|
|
169
|
+
durationMs,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Run a command with safety constraints.
|
|
176
|
+
*
|
|
177
|
+
* Security features (TR-5):
|
|
178
|
+
* - User must approve command via permission prompt before execution
|
|
179
|
+
* - Working directory is validated to be within project root
|
|
180
|
+
* - Timeout is enforced (default 30s)
|
|
181
|
+
* - No shell expansion (uses spawn, not exec)
|
|
182
|
+
* - Output is captured with size limits
|
|
183
|
+
*
|
|
184
|
+
* @param args - RunCommandArgs containing command, args, cwd, timeout, and env
|
|
185
|
+
* @param context - CodeContext with working directory
|
|
186
|
+
* @returns RunCommandResult with execution results
|
|
187
|
+
*/
|
|
188
|
+
export async function runCommand(args, context) {
|
|
189
|
+
const { command, args: commandArgs = [], cwd, timeout = DEFAULT_TIMEOUT_MS, env, } = args;
|
|
190
|
+
// Validate working directory (TR-5)
|
|
191
|
+
const cwdValidation = validateWorkingDirectory(cwd, context.workingDirectory);
|
|
192
|
+
if (!cwdValidation.valid) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
exit_code: 1,
|
|
196
|
+
stdout: "",
|
|
197
|
+
stderr: "",
|
|
198
|
+
duration_ms: 0,
|
|
199
|
+
timed_out: false,
|
|
200
|
+
error: cwdValidation.error,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const resolvedCwd = cwdValidation.resolvedPath;
|
|
204
|
+
// Validate timeout is reasonable (between 1 second and 10 minutes)
|
|
205
|
+
const effectiveTimeout = Math.max(1000, Math.min(timeout, 600000));
|
|
206
|
+
try {
|
|
207
|
+
// Execute the command
|
|
208
|
+
const result = await executeCommand(command, commandArgs, resolvedCwd, effectiveTimeout, env);
|
|
209
|
+
return {
|
|
210
|
+
success: result.exitCode === 0 && !result.timedOut,
|
|
211
|
+
exit_code: result.exitCode,
|
|
212
|
+
stdout: result.stdout,
|
|
213
|
+
stderr: result.stderr,
|
|
214
|
+
duration_ms: result.durationMs,
|
|
215
|
+
timed_out: result.timedOut,
|
|
216
|
+
error: result.timedOut
|
|
217
|
+
? `Command timed out after ${effectiveTimeout}ms`
|
|
218
|
+
: undefined,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
// Handle unexpected errors
|
|
223
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
exit_code: 1,
|
|
227
|
+
stdout: "",
|
|
228
|
+
stderr: "",
|
|
229
|
+
duration_ms: 0,
|
|
230
|
+
timed_out: false,
|
|
231
|
+
error: `Failed to execute command: ${errorMessage}`,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=run-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../../../../src/lib/local-tools/code/run-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAC,KAAK,EAAoB,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,6DAA6D;AAC7D,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,kDAAkD;AAClD,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC;;;;;;;;GAQG;AACH,SAAS,wBAAwB,CAC/B,GAAuB,EACvB,gBAAwB;IAExB,wDAAwD;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE/C,8CAA8C;IAC9C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAC,CAAC;IAC9C,CAAC;IAED,2DAA2D;IAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAEhD,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,oDAAoD;SAC5D,CAAC;IACJ,CAAC;IAED,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CACrB,MAAc,EACd,UAAkB,eAAe;IAEjC,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;QAClD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,yCAAyC;IACzC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;SAC3C,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;SACpB,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,SAAS,GAAG,0BAA0B,CAAC;AAChD,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,cAAc,CACrB,OAAe,EACf,IAAc,EACd,GAAW,EACX,OAAe,EACf,GAA4B;IAQ5B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,YAAY,GAAwB,IAAI,CAAC;QAC7C,IAAI,SAAS,GAA0B,IAAI,CAAC;QAE5C,IAAI,CAAC;YACH,oEAAoE;YACpE,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;gBAClC,GAAG;gBACH,GAAG,EAAE,EAAC,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,EAAC;gBAC7B,wCAAwC;gBACxC,KAAK,EAAE,KAAK;gBACZ,iCAAiC;gBACjC,QAAQ,EAAE,KAAK;gBACf,yCAAyC;gBACzC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;YAEH,iBAAiB;YACjB,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC1B,QAAQ,GAAG,IAAI,CAAC;gBAChB,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;oBACzC,wCAAwC;oBACxC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAC7B,8CAA8C;oBAC9C,UAAU,CAAC,GAAG,EAAE;wBACd,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;4BACzC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC;YACH,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,iCAAiC;YACjC,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;gBACxB,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;oBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACrC,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CAAC;wBACzD,MAAM,IAAI,KAAK,CAAC;oBAClB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,iCAAiC;YACjC,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;gBACxB,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;oBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACrC,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CAAC;wBACzD,MAAM,IAAI,KAAK,CAAC;oBAClB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,4BAA4B;YAC5B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBAChC,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC1B,CAAC;gBACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBAC1C,OAAO,CAAC;oBACN,QAAQ,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,wCAAwC;oBAChF,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;oBAC9B,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;oBAC9B,QAAQ;oBACR,UAAU;iBACX,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,sBAAsB;YACtB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjC,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC1B,CAAC;gBACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBAC1C,OAAO,CAAC;oBACN,QAAQ,EAAE,CAAC;oBACX,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;oBAC9B,MAAM,EAAE,cAAc,CAAC,MAAM,GAAG,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClE,QAAQ,EAAE,KAAK;oBACf,UAAU;iBACX,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,SAAS,EAAE,CAAC;gBACd,YAAY,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAC1C,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YAC3D,OAAO,CAAC;gBACN,QAAQ,EAAE,CAAC;gBACX,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,4BAA4B,YAAY,EAAE;gBAClD,QAAQ,EAAE,KAAK;gBACf,UAAU;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAoB,EACpB,OAAoB;IAEpB,MAAM,EACJ,OAAO,EACP,IAAI,EAAE,WAAW,GAAG,EAAE,EACtB,GAAG,EACH,OAAO,GAAG,kBAAkB,EAC5B,GAAG,GACJ,GAAG,IAAI,CAAC;IAET,oCAAoC;IACpC,MAAM,aAAa,GAAG,wBAAwB,CAAC,GAAG,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9E,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,aAAa,CAAC,KAAK;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC;IAE/C,mEAAmE;IACnE,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnE,IAAI,CAAC;QACH,sBAAsB;QACtB,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,OAAO,EACP,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,GAAG,CACJ,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ;YAClD,SAAS,EAAE,MAAM,CAAC,QAAQ;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,WAAW,EAAE,MAAM,CAAC,UAAU;YAC9B,SAAS,EAAE,MAAM,CAAC,QAAQ;YAC1B,KAAK,EAAE,MAAM,CAAC,QAAQ;gBACpB,CAAC,CAAC,2BAA2B,gBAAgB,IAAI;gBACjD,CAAC,CAAC,SAAS;SACd,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2BAA2B;QAC3B,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QAC3D,OAAO;YACL,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,8BAA8B,YAAY,EAAE;SACpD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* search_files tool - Search for files matching a glob pattern.
|
|
3
|
+
* Supports .gitignore respect, exclude patterns, and result limits.
|
|
4
|
+
*
|
|
5
|
+
* Security: Implements path validation to prevent directory traversal (TR-5).
|
|
6
|
+
* Respects .gitignore by default and skips common ignored directories.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs/promises";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
// Default maximum results to return
|
|
11
|
+
const DEFAULT_MAX_RESULTS = 100;
|
|
12
|
+
// Directories to always skip unless explicitly requested (TR-5)
|
|
13
|
+
const DEFAULT_IGNORED_DIRS = new Set([
|
|
14
|
+
"node_modules",
|
|
15
|
+
".git",
|
|
16
|
+
"__pycache__",
|
|
17
|
+
".pytest_cache",
|
|
18
|
+
".mypy_cache",
|
|
19
|
+
".tox",
|
|
20
|
+
".nox",
|
|
21
|
+
".eggs",
|
|
22
|
+
"*.egg-info",
|
|
23
|
+
".venv",
|
|
24
|
+
"venv",
|
|
25
|
+
"env",
|
|
26
|
+
".env",
|
|
27
|
+
"dist",
|
|
28
|
+
"build",
|
|
29
|
+
".next",
|
|
30
|
+
".nuxt",
|
|
31
|
+
".output",
|
|
32
|
+
".cache",
|
|
33
|
+
".parcel-cache",
|
|
34
|
+
"coverage",
|
|
35
|
+
".nyc_output",
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Parse a .gitignore file and return an array of patterns.
|
|
39
|
+
*/
|
|
40
|
+
async function parseGitignore(gitignorePath) {
|
|
41
|
+
try {
|
|
42
|
+
const content = await fs.readFile(gitignorePath, "utf-8");
|
|
43
|
+
return content
|
|
44
|
+
.split("\n")
|
|
45
|
+
.map((line) => line.trim())
|
|
46
|
+
.filter((line) => line && !line.startsWith("#"));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Convert a glob pattern to a RegExp.
|
|
54
|
+
* Supports *, **, and ? wildcards.
|
|
55
|
+
*/
|
|
56
|
+
function globToRegex(pattern) {
|
|
57
|
+
// Escape special regex characters except glob wildcards
|
|
58
|
+
let regexStr = pattern
|
|
59
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
60
|
+
// Handle ** (matches any path including separators)
|
|
61
|
+
.replace(/\*\*/g, "{{GLOBSTAR}}")
|
|
62
|
+
// Handle * (matches anything except path separator)
|
|
63
|
+
.replace(/\*/g, "[^/]*")
|
|
64
|
+
// Handle ? (matches single character except path separator)
|
|
65
|
+
.replace(/\?/g, "[^/]")
|
|
66
|
+
// Restore globstar
|
|
67
|
+
.replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
68
|
+
return new RegExp(`^${regexStr}$`, "i");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if a path matches a glob pattern.
|
|
72
|
+
*/
|
|
73
|
+
function matchesGlob(filePath, pattern) {
|
|
74
|
+
// Normalize path separators
|
|
75
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
76
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
77
|
+
// Handle patterns that start with /
|
|
78
|
+
const patternToUse = normalizedPattern.startsWith("/")
|
|
79
|
+
? normalizedPattern.slice(1)
|
|
80
|
+
: normalizedPattern;
|
|
81
|
+
const regex = globToRegex(patternToUse);
|
|
82
|
+
return regex.test(normalizedPath);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if a path should be ignored based on gitignore patterns.
|
|
86
|
+
*/
|
|
87
|
+
function isIgnoredByPatterns(relativePath, patterns) {
|
|
88
|
+
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
89
|
+
for (const pattern of patterns) {
|
|
90
|
+
if (!pattern)
|
|
91
|
+
continue;
|
|
92
|
+
// Handle negation patterns (!)
|
|
93
|
+
if (pattern.startsWith("!")) {
|
|
94
|
+
// Negation - if it matches, it's NOT ignored
|
|
95
|
+
const negatedPattern = pattern.slice(1);
|
|
96
|
+
if (matchesGlob(normalizedPath, negatedPattern)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// Handle directory-only patterns (ending with /)
|
|
102
|
+
const isDirectoryPattern = pattern.endsWith("/");
|
|
103
|
+
const cleanPattern = isDirectoryPattern ? pattern.slice(0, -1) : pattern;
|
|
104
|
+
// Check if pattern matches
|
|
105
|
+
if (matchesGlob(normalizedPath, cleanPattern)) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
// Also check if any path component matches (for patterns like "node_modules")
|
|
109
|
+
const pathParts = normalizedPath.split("/");
|
|
110
|
+
for (const part of pathParts) {
|
|
111
|
+
if (matchesGlob(part, cleanPattern)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Check with ** prefix for patterns that should match anywhere
|
|
116
|
+
if (!cleanPattern.includes("/") && !cleanPattern.startsWith("*")) {
|
|
117
|
+
if (matchesGlob(normalizedPath, `**/${cleanPattern}`)) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if a directory name is in the default ignored list.
|
|
126
|
+
*/
|
|
127
|
+
function isDefaultIgnoredDir(dirName) {
|
|
128
|
+
return DEFAULT_IGNORED_DIRS.has(dirName);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Validate and resolve a path to prevent directory traversal.
|
|
132
|
+
* Returns the resolved absolute path if valid, or an error.
|
|
133
|
+
*
|
|
134
|
+
* Security (TR-5):
|
|
135
|
+
* - All paths normalized and validated against project root
|
|
136
|
+
* - Reject paths containing `..` that escape root
|
|
137
|
+
*/
|
|
138
|
+
function validatePath(targetPath, workingDirectory) {
|
|
139
|
+
const rootDir = path.resolve(workingDirectory);
|
|
140
|
+
const resolvedPath = path.resolve(rootDir, targetPath);
|
|
141
|
+
// Security check: ensure resolved path is within root directory
|
|
142
|
+
const normalizedRoot = rootDir.endsWith(path.sep)
|
|
143
|
+
? rootDir
|
|
144
|
+
: rootDir + path.sep;
|
|
145
|
+
const normalizedResolved = resolvedPath + path.sep;
|
|
146
|
+
if (!normalizedResolved.startsWith(normalizedRoot) &&
|
|
147
|
+
resolvedPath !== rootDir) {
|
|
148
|
+
return {
|
|
149
|
+
valid: false,
|
|
150
|
+
error: "Path validation failed: access denied",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return { valid: true, resolvedPath };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Recursively search for files matching a glob pattern.
|
|
157
|
+
*/
|
|
158
|
+
async function searchRecursive(currentDir, rootDir, pattern, options) {
|
|
159
|
+
// Check if we've reached the max results
|
|
160
|
+
if (options.results.length >= options.maxResults) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
// Check max results limit
|
|
167
|
+
if (options.results.length >= options.maxResults) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
171
|
+
const relativePath = path.relative(rootDir, fullPath);
|
|
172
|
+
// Skip default ignored directories (TR-5)
|
|
173
|
+
if (entry.isDirectory() && isDefaultIgnoredDir(entry.name)) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
// Check gitignore patterns if enabled
|
|
177
|
+
if (options.respectGitignore &&
|
|
178
|
+
isIgnoredByPatterns(relativePath, options.gitignorePatterns)) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
// Check exclude patterns
|
|
182
|
+
if (isIgnoredByPatterns(relativePath, options.excludePatterns)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (entry.isDirectory()) {
|
|
186
|
+
// Recurse into subdirectory
|
|
187
|
+
await searchRecursive(currentDir + path.sep + entry.name, rootDir, pattern, options);
|
|
188
|
+
}
|
|
189
|
+
else if (entry.isFile()) {
|
|
190
|
+
// Check if file matches the search pattern
|
|
191
|
+
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
192
|
+
if (pattern.test(normalizedRelativePath)) {
|
|
193
|
+
options.results.push(relativePath);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Skip directories we can't read (permission issues, etc.)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Search for files matching a glob pattern.
|
|
204
|
+
*
|
|
205
|
+
* @param args - SearchFilesArgs containing pattern and options
|
|
206
|
+
* @param context - CodeContext with working directory
|
|
207
|
+
* @returns SearchFilesResult with matching files
|
|
208
|
+
*/
|
|
209
|
+
export async function searchFiles(args, context) {
|
|
210
|
+
const { pattern, path: basePath = ".", exclude = [], respect_gitignore = true, max_results = DEFAULT_MAX_RESULTS, } = args;
|
|
211
|
+
// Validate the base path
|
|
212
|
+
const pathValidation = validatePath(basePath, context.workingDirectory);
|
|
213
|
+
if (!pathValidation.valid) {
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
files: [],
|
|
217
|
+
total_found: 0,
|
|
218
|
+
truncated: false,
|
|
219
|
+
error: pathValidation.error,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const resolvedBasePath = pathValidation.resolvedPath;
|
|
223
|
+
try {
|
|
224
|
+
// Check if base path exists and is a directory
|
|
225
|
+
const stats = await fs.stat(resolvedBasePath);
|
|
226
|
+
if (!stats.isDirectory()) {
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
files: [],
|
|
230
|
+
total_found: 0,
|
|
231
|
+
truncated: false,
|
|
232
|
+
error: "Base path is not a directory",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// Parse .gitignore if respect_gitignore is enabled
|
|
236
|
+
let gitignorePatterns = [];
|
|
237
|
+
if (respect_gitignore) {
|
|
238
|
+
const gitignorePath = path.join(context.workingDirectory, ".gitignore");
|
|
239
|
+
gitignorePatterns = await parseGitignore(gitignorePath);
|
|
240
|
+
}
|
|
241
|
+
// Convert the search pattern to a regex
|
|
242
|
+
const searchRegex = globToRegex(pattern);
|
|
243
|
+
// Search for matching files
|
|
244
|
+
const results = [];
|
|
245
|
+
await searchRecursive(resolvedBasePath, resolvedBasePath, searchRegex, {
|
|
246
|
+
gitignorePatterns,
|
|
247
|
+
excludePatterns: exclude,
|
|
248
|
+
respectGitignore: respect_gitignore,
|
|
249
|
+
maxResults: max_results + 1, // Get one extra to detect truncation
|
|
250
|
+
results,
|
|
251
|
+
});
|
|
252
|
+
// Check if results were truncated
|
|
253
|
+
const truncated = results.length > max_results;
|
|
254
|
+
const finalResults = truncated ? results.slice(0, max_results) : results;
|
|
255
|
+
// Sort results alphabetically for consistent output
|
|
256
|
+
finalResults.sort((a, b) => a.localeCompare(b));
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
files: finalResults,
|
|
260
|
+
total_found: finalResults.length,
|
|
261
|
+
truncated,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
// Handle specific error types without exposing sensitive info (TR-5)
|
|
266
|
+
if (error instanceof Error) {
|
|
267
|
+
const nodeError = error;
|
|
268
|
+
if (nodeError.code === "ENOENT") {
|
|
269
|
+
return {
|
|
270
|
+
success: false,
|
|
271
|
+
files: [],
|
|
272
|
+
total_found: 0,
|
|
273
|
+
truncated: false,
|
|
274
|
+
error: "Base path not found",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
if (nodeError.code === "EACCES") {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
files: [],
|
|
281
|
+
total_found: 0,
|
|
282
|
+
truncated: false,
|
|
283
|
+
error: "Permission denied",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Generic error without exposing details (TR-5)
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
files: [],
|
|
291
|
+
total_found: 0,
|
|
292
|
+
truncated: false,
|
|
293
|
+
error: "Failed to search files",
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=search-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-files.js","sourceRoot":"","sources":["../../../../../src/lib/local-tools/code/search-files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,oCAAoC;AACpC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,gEAAgE;AAChE,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,MAAM;IACN,aAAa;IACb,eAAe;IACf,aAAa;IACb,MAAM;IACN,MAAM;IACN,OAAO;IACP,YAAY;IACZ,OAAO;IACP,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,SAAS;IACT,QAAQ;IACR,eAAe;IACf,UAAU;IACV,aAAa;CACd,CAAC,CAAC;AAEH;;GAEG;AACH,KAAK,UAAU,cAAc,CAAC,aAAqB;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,OAAO;aACX,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAe;IAClC,wDAAwD;IACxD,IAAI,QAAQ,GAAG,OAAO;SACnB,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,oDAAoD;SACnD,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC;QACjC,oDAAoD;SACnD,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;QACxB,4DAA4D;SAC3D,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,mBAAmB;SAClB,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;IAEtC,OAAO,IAAI,MAAM,CAAC,IAAI,QAAQ,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,QAAgB,EAAE,OAAe;IACpD,4BAA4B;IAC5B,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEtD,oCAAoC;IACpC,MAAM,YAAY,GAAG,iBAAiB,CAAC,UAAU,CAAC,GAAG,CAAC;QACpD,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,iBAAiB,CAAC;IAEtB,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAC1B,YAAoB,EACpB,QAAkB;IAElB,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAExD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,+BAA+B;QAC/B,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,6CAA6C;YAC7C,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,WAAW,CAAC,cAAc,EAAE,cAAc,CAAC,EAAE,CAAC;gBAChD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,SAAS;QACX,CAAC;QAED,iDAAiD;QACjD,MAAM,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEzE,2BAA2B;QAC3B,IAAI,WAAW,CAAC,cAAc,EAAE,YAAY,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,8EAA8E;QAC9E,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;gBACpC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,+DAA+D;QAC/D,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,IAAI,WAAW,CAAC,cAAc,EAAE,MAAM,YAAY,EAAE,CAAC,EAAE,CAAC;gBACtD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,OAAe;IAC1C,OAAO,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CACnB,UAAkB,EAClB,gBAAwB;IAExB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAEvD,gEAAgE;IAChE,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,KAAK,UAAU,eAAe,CAC5B,UAAkB,EAClB,OAAe,EACf,OAAe,EACf,OAMC;IAED,yCAAyC;IACzC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACjD,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAC,aAAa,EAAE,IAAI,EAAC,CAAC,CAAC;QAEpE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,0BAA0B;YAC1B,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACjD,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEtD,0CAA0C;YAC1C,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3D,SAAS;YACX,CAAC;YAED,sCAAsC;YACtC,IACE,OAAO,CAAC,gBAAgB;gBACxB,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC,iBAAiB,CAAC,EAC5D,CAAC;gBACD,SAAS;YACX,CAAC;YAED,yBAAyB;YACzB,IAAI,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;gBAC/D,SAAS;YACX,CAAC;YAED,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,4BAA4B;gBAC5B,MAAM,eAAe,CACnB,UAAU,GAAG,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,IAAI,EAClC,OAAO,EACP,OAAO,EACP,OAAO,CACR,CAAC;YACJ,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,2CAA2C;gBAC3C,MAAM,sBAAsB,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAChE,IAAI,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;oBACzC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;IAC7D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAqB,EACrB,OAAoB;IAEpB,MAAM,EACJ,OAAO,EACP,IAAI,EAAE,QAAQ,GAAG,GAAG,EACpB,OAAO,GAAG,EAAE,EACZ,iBAAiB,GAAG,IAAI,EACxB,WAAW,GAAG,mBAAmB,GAClC,GAAG,IAAI,CAAC;IAET,yBAAyB;IACzB,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,KAAK,EAAE,EAAE;YACT,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,cAAc,CAAC,KAAK;SAC5B,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,cAAc,CAAC,YAAY,CAAC;IAErD,IAAI,CAAC;QACH,+CAA+C;QAC/C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE;gBACT,WAAW,EAAE,CAAC;gBACd,SAAS,EAAE,KAAK;gBAChB,KAAK,EAAE,8BAA8B;aACtC,CAAC;QACJ,CAAC;QAED,mDAAmD;QACnD,IAAI,iBAAiB,GAAa,EAAE,CAAC;QACrC,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;YACxE,iBAAiB,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,CAAC;QAC1D,CAAC;QAED,wCAAwC;QACxC,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAEzC,4BAA4B;QAC5B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,eAAe,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE;YACrE,iBAAiB;YACjB,eAAe,EAAE,OAAO;YACxB,gBAAgB,EAAE,iBAAiB;YACnC,UAAU,EAAE,WAAW,GAAG,CAAC,EAAE,qCAAqC;YAClE,OAAO;SACR,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,WAAW,CAAC;QAC/C,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEzE,oDAAoD;QACpD,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,YAAY;YACnB,WAAW,EAAE,YAAY,CAAC,MAAM;YAChC,SAAS;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,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,KAAK,EAAE,EAAE;oBACT,WAAW,EAAE,CAAC;oBACd,SAAS,EAAE,KAAK;oBAChB,KAAK,EAAE,qBAAqB;iBAC7B,CAAC;YACJ,CAAC;YACD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAChC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,EAAE;oBACT,WAAW,EAAE,CAAC;oBACd,SAAS,EAAE,KAAK;oBAChB,KAAK,EAAE,mBAAmB;iBAC3B,CAAC;YACJ,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,EAAE;YACT,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,wBAAwB;SAChC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/lib/local-tools/code/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Guard - Controls access to sensitive operations
|
|
3
|
+
* Prompts user for permission before executing file writes or shell commands
|
|
4
|
+
*/
|
|
5
|
+
export class PermissionGuard {
|
|
6
|
+
sessionGrants;
|
|
7
|
+
promptFn = null;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.sessionGrants = {
|
|
10
|
+
file_write: false,
|
|
11
|
+
file_delete: false,
|
|
12
|
+
run_command: false,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Set the prompt function that will be called when permission is needed
|
|
17
|
+
*/
|
|
18
|
+
setPromptFn(fn) {
|
|
19
|
+
this.promptFn = fn;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if an operation is allowed
|
|
23
|
+
* Returns immediately if session grant exists, otherwise prompts user
|
|
24
|
+
*/
|
|
25
|
+
async check(request) {
|
|
26
|
+
// If session grant exists, allow immediately
|
|
27
|
+
if (this.sessionGrants[request.category]) {
|
|
28
|
+
return { allowed: true };
|
|
29
|
+
}
|
|
30
|
+
// If no prompt function set, deny by default (fail-safe)
|
|
31
|
+
if (!this.promptFn) {
|
|
32
|
+
return {
|
|
33
|
+
allowed: false,
|
|
34
|
+
feedback: `Permission required for ${request.category}. No permission handler configured.`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Prompt user for permission
|
|
38
|
+
const response = await this.promptFn(request);
|
|
39
|
+
switch (response) {
|
|
40
|
+
case "allow_session":
|
|
41
|
+
this.grantSession(request.category);
|
|
42
|
+
return { allowed: true };
|
|
43
|
+
case "allow_once":
|
|
44
|
+
return { allowed: true };
|
|
45
|
+
case "deny":
|
|
46
|
+
default:
|
|
47
|
+
return {
|
|
48
|
+
allowed: false,
|
|
49
|
+
feedback: this.buildDenyFeedback(request),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Grant session-wide permission for a category
|
|
55
|
+
*/
|
|
56
|
+
grantSession(category) {
|
|
57
|
+
this.sessionGrants[category] = true;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if a category has session-wide permission
|
|
61
|
+
*/
|
|
62
|
+
hasSessionGrant(category) {
|
|
63
|
+
return this.sessionGrants[category];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Reset all session grants
|
|
67
|
+
*/
|
|
68
|
+
reset() {
|
|
69
|
+
this.sessionGrants = {
|
|
70
|
+
file_write: false,
|
|
71
|
+
file_delete: false,
|
|
72
|
+
run_command: false,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build feedback message for denied operations
|
|
77
|
+
*/
|
|
78
|
+
buildDenyFeedback(request) {
|
|
79
|
+
const { category, details } = request;
|
|
80
|
+
switch (category) {
|
|
81
|
+
case "run_command":
|
|
82
|
+
return `User denied permission to run command: ${details.command}${details.args?.length ? ` ${details.args.join(" ")}` : ""}. Please suggest an alternative approach or ask the user what they'd like to do instead.`;
|
|
83
|
+
case "file_write":
|
|
84
|
+
return `User denied permission to write to: ${details.path}. Please suggest an alternative approach or ask the user what they'd like to do instead.`;
|
|
85
|
+
case "file_delete":
|
|
86
|
+
return `User denied permission to delete: ${details.path}. Please suggest an alternative approach or ask the user what they'd like to do instead.`;
|
|
87
|
+
default:
|
|
88
|
+
return `User denied permission for ${category}. Please suggest an alternative approach.`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Singleton instance for use across the application
|
|
93
|
+
export const permissionGuard = new PermissionGuard();
|
|
94
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/lib/permissions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH,MAAM,OAAO,eAAe;IAClB,aAAa,CAAqB;IAClC,QAAQ,GAA8B,IAAI,CAAC;IAEnD;QACE,IAAI,CAAC,aAAa,GAAG;YACnB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,KAAK;SACnB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,EAAsB;QAChC,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,OAA0B;QACpC,6CAA6C;QAC7C,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC;QACzB,CAAC;QAED,yDAAyD;QACzD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,2BAA2B,OAAO,CAAC,QAAQ,qCAAqC;aAC3F,CAAC;QACJ,CAAC;QAED,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE9C,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,eAAe;gBAClB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACpC,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC;YAEzB,KAAK,YAAY;gBACf,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC;YAEzB,KAAK,MAAM,CAAC;YACZ;gBACE,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;iBAC1C,CAAC;QACN,CAAC;IACH,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAA4B;QACvC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,QAA4B;QAC1C,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,aAAa,GAAG;YACnB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,KAAK;SACnB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,OAA0B;QAClD,MAAM,EAAC,QAAQ,EAAE,OAAO,EAAC,GAAG,OAAO,CAAC;QAEpC,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,aAAa;gBAChB,OAAO,0CAA0C,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,0FAA0F,CAAC;YAExN,KAAK,YAAY;gBACf,OAAO,uCAAuC,OAAO,CAAC,IAAI,0FAA0F,CAAC;YAEvJ,KAAK,aAAa;gBAChB,OAAO,qCAAqC,OAAO,CAAC,IAAI,0FAA0F,CAAC;YAErJ;gBACE,OAAO,8BAA8B,QAAQ,2CAA2C,CAAC;QAC7F,CAAC;IACH,CAAC;CACF;AAED,oDAAoD;AACpD,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
|