()
| 182 | // HTTP scan helper — extracts connections, discovers handler/client files |
| 183 | let httpConnectionsContext = ''; |
| 184 | const runHttpScan = async () => { |
| 185 | log(`\nScanning all source files for HTTP connections...`); |
| 186 | webview.updateLoadingText('Scanning HTTP connections...', `Reading source files`); |
| 187 | const httpScanSourceFiles = await WorkflowDetector.getAllSourceFiles(); |
| 188 | const httpSourceContents: { path: string; content: string }[] = []; |
| 189 | let httpScanned = 0; |
| 190 | |
| 191 | for (const uri of httpScanSourceFiles) { |
| 192 | const relativePath = vscode.workspace.asRelativePath(uri, false); |
| 193 | if (!workflowPaths.has(relativePath)) { |
| 194 | try { |
| 195 | const content = await vscode.workspace.fs.readFile(uri); |
| 196 | httpSourceContents.push({ |
| 197 | path: relativePath, |
| 198 | content: Buffer.from(content).toString('utf8') |
| 199 | }); |
| 200 | } catch (error) { |
| 201 | // Skip files that can't be read |
| 202 | } |
| 203 | } |
| 204 | httpScanned++; |
| 205 | if (httpScanned % 100 === 0 || httpScanned === httpScanSourceFiles.length) { |
| 206 | webview.updateLoadingText( |
| 207 | 'Scanning HTTP connections...', |
| 208 | `${httpScanned.toLocaleString()} / ${httpScanSourceFiles.length.toLocaleString()} files read` |
| 209 | ); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | const allFilesForHttpExtraction = [...allFileContents, ...httpSourceContents]; |
| 214 | webview.updateLoadingText('Extracting HTTP connections...', `Processing ${allFilesForHttpExtraction.length.toLocaleString()} files`); |
| 215 | log(`Scanning ${allFilesForHttpExtraction.length} files (${allFileContents.length} LLM + ${httpSourceContents.length} other)`); |
| 216 | |
| 217 | const rawHttpStructure = extractRepoStructure(allFilesForHttpExtraction); |
| 218 | const allHttpConnections = rawHttpStructure.httpConnections; |
| 219 | setHttpConnections(allHttpConnections); |
| 220 | setCrossFileCalls(rawHttpStructure.crossFileCalls || []); |
| 221 | setRepoFiles(rawHttpStructure.files.map(f => ({ |
| 222 | path: f.path, |
| 223 | functions: f.functions.map(fn => ({ name: fn.name, calls: fn.calls, line: fn.line })) |
| 224 | }))); |
| 225 | pipelineStats.analyzed.httpConnections = allHttpConnections.length; |
| 226 | pipelineStats.detected.httpFiles = httpSourceContents.length; |
| 227 | httpConnectionsContext = formatHttpConnectionsForPrompt(rawHttpStructure); |
| 228 | if (allHttpConnections.length > 0) { |
| 229 | log(`Found ${allHttpConnections.length} HTTP connection(s) between services:`); |
| 230 | for (const conn of allHttpConnections) { |
| 231 | log(` ${vscode.workspace.asRelativePath(conn.client.file)}::${conn.client.function} → ${vscode.workspace.asRelativePath(conn.handler.file)}::${conn.handler.function}`); |
| 232 | log(` (${conn.client.method} ${conn.client.normalizedPath})`); |
| 233 | } |
| 234 | } else { |
| 235 | log(`No HTTP connections detected`); |
| 236 | } |
| 237 | |
| 238 | // Discover additional files via HTTP handler tracing (only needed for first run) |
| 239 | if (isFirstRun) { |
| 240 | const allHttpHandlers = new Set<string>(); |
| 241 | for (const conn of allHttpConnections) { |
no test coverage detected