c118996746
- SwiftUI macOS app with C++17 code analysis engine (ObjC++ bridge) - Agentic AI loop: LLM plans → tool calls → execution → feedback loop - 15 agent tools: file ops, terminal, git, xcode build, code intel - 7 persistent terminal tools with background session management - Chat sidebar with agent step rendering and auto-apply - NVIDIA NIM API integration (Llama 3.3 70B default) - OpenAI tool_calls format with prompt-based fallback - Code editor with syntax highlighting and multi-tab support - File tree, console view, terminal view - Git integration and workspace management
195 lines
7.8 KiB
Swift
195 lines
7.8 KiB
Swift
import Foundation
|
|
|
|
// ─── Errors ──────────────────────────────────────────────────────
|
|
|
|
enum IDEError: Error, LocalizedError {
|
|
case compilationFailed(String)
|
|
case runtimeError(String)
|
|
case permissionDenied
|
|
case timeout
|
|
case fileWriteError(String)
|
|
case cancelled
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .compilationFailed(let msg): return "Compilation failed: \(msg)"
|
|
case .runtimeError(let msg): return "Runtime error: \(msg)"
|
|
case .permissionDenied: return "Permission denied."
|
|
case .timeout: return "Execution timed out."
|
|
case .fileWriteError(let msg): return "File write error: \(msg)"
|
|
case .cancelled: return "Execution cancelled."
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── C++ Engine Swift Facade ─────────────────────────────────────
|
|
|
|
struct CppAnalysisConfig {
|
|
var maxLineLength: Int = 120
|
|
var maxNestingDepth: Int = 5
|
|
var maxFunctionLength: Int = 50
|
|
var minCommentRatio: Double = 0.05
|
|
var detectForceUnwraps: Bool = true
|
|
var detectForceTry: Bool = true
|
|
var detectForceCast: Bool = true
|
|
var detectDuplicateLines: Bool = true
|
|
var detectTodoFixme: Bool = true
|
|
var detectRetainCycles: Bool = true
|
|
}
|
|
|
|
final class CppEngineController {
|
|
private let wrapper: SwiftEngineWrapper
|
|
|
|
init() {
|
|
wrapper = SwiftEngineWrapper()
|
|
}
|
|
|
|
// ── Configuration ────────────────────────────────────────────
|
|
|
|
func applyConfig(_ config: CppAnalysisConfig) {
|
|
wrapper.setMaxLineLength(config.maxLineLength)
|
|
wrapper.setMaxNestingDepth(config.maxNestingDepth)
|
|
wrapper.setMaxFunctionLength(config.maxFunctionLength)
|
|
wrapper.setMinCommentRatio(config.minCommentRatio)
|
|
wrapper.setDetectForceUnwraps(config.detectForceUnwraps)
|
|
wrapper.setDetectForceTry(config.detectForceTry)
|
|
wrapper.setDetectForceCast(config.detectForceCast)
|
|
wrapper.setDetectDuplicateLines(config.detectDuplicateLines)
|
|
wrapper.setDetectTodoFixme(config.detectTodoFixme)
|
|
wrapper.setDetectRetainCycles(config.detectRetainCycles)
|
|
}
|
|
|
|
// ── Analysis ─────────────────────────────────────────────────
|
|
|
|
func runAnalysis(_ code: String) -> String {
|
|
wrapper.runAnalysis(code)
|
|
}
|
|
|
|
func runStructuredAnalysis(_ code: String) -> [String: Any] {
|
|
(wrapper.runStructuredAnalysis(code) as [String: Any]?) ?? [:]
|
|
}
|
|
|
|
// ── Metrics ──────────────────────────────────────────────────
|
|
|
|
func checksum(_ code: String) -> Int { wrapper.getChecksum(code) }
|
|
func lineCount(_ code: String) -> Int { wrapper.countLines(code) }
|
|
func blankLineCount(_ code: String) -> Int { wrapper.countBlankLines(code) }
|
|
func codeLineCount(_ code: String) -> Int { wrapper.countCodeLines(code) }
|
|
func functionCount(_ code: String) -> Int { wrapper.countFunctions(code) }
|
|
func classCount(_ code: String) -> Int { wrapper.countClasses(code) }
|
|
func structCount(_ code: String) -> Int { wrapper.countStructs(code) }
|
|
func enumCount(_ code: String) -> Int { wrapper.countEnums(code) }
|
|
func protocolCount(_ code: String) -> Int { wrapper.countProtocols(code) }
|
|
|
|
// ── Complexity ───────────────────────────────────────────────
|
|
|
|
func complexity(_ code: String) -> String { wrapper.estimateComplexity(code) }
|
|
func cyclomaticComplexity(_ code: String) -> Int { wrapper.cyclomaticComplexity(code) }
|
|
func maintainabilityIndex(_ code: String) -> Double { wrapper.maintainabilityIndex(code) }
|
|
func bracesBalanced(_ code: String) -> Bool { wrapper.checkBalancedBraces(code) }
|
|
func commentRatio(_ code: String) -> Double { wrapper.commentRatio(code) }
|
|
|
|
// ── Extraction ───────────────────────────────────────────────
|
|
|
|
func keywords(_ code: String) -> [String] { wrapper.extractKeywords(code) }
|
|
func issues(_ code: String) -> [String] { wrapper.findIssues(code) }
|
|
func imports(_ code: String) -> [String] { wrapper.extractImports(code) }
|
|
|
|
func symbols(_ code: String) -> [[String: Any]] {
|
|
(wrapper.extractSymbols(code) as [[String: Any]]?) ?? []
|
|
}
|
|
|
|
func duplicateLines(_ code: String) -> [[String: Any]] {
|
|
(wrapper.detectDuplicateLines(code) as [[String: Any]]?) ?? []
|
|
}
|
|
|
|
func todoComments(_ code: String) -> [[String: Any]] {
|
|
(wrapper.extractTodoComments(code) as [[String: Any]]?) ?? []
|
|
}
|
|
|
|
// ── Indentation ──────────────────────────────────────────────
|
|
|
|
func suggestIndentation(codeBefore: String, tabWidth: Int = 4) -> Int {
|
|
wrapper.suggestIndentation(codeBefore, tabWidth: tabWidth)
|
|
}
|
|
}
|
|
|
|
// ─── Runtime Engine ──────────────────────────────────────────────
|
|
|
|
final class SwiftRuntimeEngine: CodeEngineProtocol {
|
|
private let projectDirectory: URL
|
|
private let timeoutSeconds: TimeInterval
|
|
private var currentProcess: Process?
|
|
|
|
init(projectDirectory: URL, timeoutSeconds: TimeInterval = 30) {
|
|
self.projectDirectory = projectDirectory
|
|
self.timeoutSeconds = timeoutSeconds
|
|
}
|
|
|
|
func execute(script: String) async throws -> String {
|
|
let fileID = UUID().uuidString
|
|
let tempFile = projectDirectory.appendingPathComponent("cxide_run_\(fileID).swift")
|
|
|
|
do {
|
|
try script.write(to: tempFile, atomically: true, encoding: .utf8)
|
|
} catch {
|
|
throw IDEError.fileWriteError(error.localizedDescription)
|
|
}
|
|
|
|
defer { try? FileManager.default.removeItem(at: tempFile) }
|
|
|
|
let process = Process()
|
|
process.executableURL = URL(fileURLWithPath: "/usr/bin/swift")
|
|
process.arguments = [tempFile.path]
|
|
process.currentDirectoryURL = projectDirectory
|
|
|
|
let stdoutPipe = Pipe()
|
|
let stderrPipe = Pipe()
|
|
process.standardOutput = stdoutPipe
|
|
process.standardError = stderrPipe
|
|
|
|
currentProcess = process
|
|
|
|
do {
|
|
try process.run()
|
|
} catch {
|
|
currentProcess = nil
|
|
throw IDEError.compilationFailed(error.localizedDescription)
|
|
}
|
|
|
|
// Timeout handling
|
|
let timer = DispatchSource.makeTimerSource(queue: .global())
|
|
timer.schedule(deadline: .now() + timeoutSeconds)
|
|
timer.setEventHandler { [weak process] in
|
|
process?.terminate()
|
|
}
|
|
timer.resume()
|
|
|
|
process.waitUntilExit()
|
|
timer.cancel()
|
|
currentProcess = nil
|
|
|
|
let outData = stdoutPipe.fileHandleForReading.readDataToEndOfFile()
|
|
let errData = stderrPipe.fileHandleForReading.readDataToEndOfFile()
|
|
|
|
let stdout = String(data: outData, encoding: .utf8) ?? ""
|
|
let stderr = String(data: errData, encoding: .utf8) ?? ""
|
|
|
|
guard process.terminationStatus == 0 else {
|
|
let detail = stderr.isEmpty ? "Exit code \(process.terminationStatus)" : stderr
|
|
throw IDEError.compilationFailed(detail)
|
|
}
|
|
|
|
return stdout
|
|
}
|
|
|
|
func cancel() {
|
|
currentProcess?.terminate()
|
|
currentProcess = nil
|
|
}
|
|
|
|
func analyze(script: String) async throws -> [Diagnostic] {
|
|
return []
|
|
}
|
|
}
|