Files
CxIDE/SwiftCodeEngine.swift
T
cx-git-agent c118996746 feat: CxIDE v1 — native macOS SwiftUI IDE with agentic AI assistant
- 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
2026-04-21 16:05:52 -05:00

134 lines
4.5 KiB
Swift

import Foundation
struct ExecutionResult: Sendable {
let stdout: String
let stderr: String
let exitCode: Int32
let duration: TimeInterval
var succeeded: Bool { exitCode == 0 }
var formattedOutput: String {
var parts: [String] = []
if !stdout.isEmpty { parts.append(stdout) }
if !stderr.isEmpty { parts.append(stderr) }
parts.append("Exit code: \(exitCode) (\(String(format: "%.2fs", duration)))")
return parts.joined(separator: "\n")
}
}
enum CodeExecutionError: Error, LocalizedError {
case notSupportedPlatform
case failedToLaunch(String)
case timeout
case cancelled
var errorDescription: String? {
switch self {
case .notSupportedPlatform:
return "Code execution is not supported on this platform."
case .failedToLaunch(let reason):
return "Failed to launch process: \(reason)"
case .timeout:
return "Execution timed out."
case .cancelled:
return "Execution was cancelled."
}
}
}
protocol CodeEngine: AnyObject {
func run(_ source: String) async throws -> ExecutionResult
func cancel()
}
final class SwiftCodeEngine: CodeEngine, @unchecked Sendable {
private var currentProcess: Process?
private let lock = NSLock()
private let timeoutInterval: TimeInterval
init(timeoutInterval: TimeInterval = 30) {
self.timeoutInterval = timeoutInterval
}
func run(_ source: String) async throws -> ExecutionResult {
#if os(macOS)
let startTime = CFAbsoluteTimeGetCurrent()
return try await withCheckedThrowingContinuation { continuation in
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self else {
continuation.resume(throwing: CodeExecutionError.cancelled)
return
}
let tempDir = FileManager.default.temporaryDirectory
let fileURL = tempDir.appendingPathComponent("CxIDE-\(UUID().uuidString).swift")
do {
try source.write(to: fileURL, atomically: true, encoding: .utf8)
defer { try? FileManager.default.removeItem(at: fileURL) }
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/xcrun")
process.arguments = ["swift", fileURL.path]
process.currentDirectoryURL = tempDir
let stdoutPipe = Pipe()
let stderrPipe = Pipe()
process.standardOutput = stdoutPipe
process.standardError = stderrPipe
self.lock.lock()
self.currentProcess = process
self.lock.unlock()
try process.run()
// Timeout handling
let timer = DispatchSource.makeTimerSource(queue: .global())
timer.schedule(deadline: .now() + self.timeoutInterval)
timer.setEventHandler {
process.terminate()
}
timer.resume()
process.waitUntilExit()
timer.cancel()
self.lock.lock()
self.currentProcess = nil
self.lock.unlock()
let outData = stdoutPipe.fileHandleForReading.readDataToEndOfFile()
let errData = stderrPipe.fileHandleForReading.readDataToEndOfFile()
let stdout = String(data: outData, encoding: .utf8) ?? ""
let stderr = String(data: errData, encoding: .utf8) ?? ""
let duration = CFAbsoluteTimeGetCurrent() - startTime
let result = ExecutionResult(
stdout: stdout,
stderr: stderr,
exitCode: process.terminationStatus,
duration: duration
)
continuation.resume(returning: result)
} catch {
continuation.resume(throwing: CodeExecutionError.failedToLaunch(error.localizedDescription))
}
}
}
#else
throw CodeExecutionError.notSupportedPlatform
#endif
}
func cancel() {
lock.lock()
currentProcess?.terminate()
currentProcess = nil
lock.unlock()
}
}