Skip to content

Commit cc9a48e

Browse files
kochj23claude
andcommitted
fix(low-info): Resolve 10 LOW/INFO audit findings
- Replace vague TODOs with specific requirements in MLXSwiftBackend, SlashCommandHandler, EditTool, TestGenerationTool - Implement Clear Conversations confirmation dialog in SettingsView - Replace force unwraps with safe optionals in MLXService - Add @available deprecated attribute to unused ContentView - Replace NSString casts with URL API in SlashCommandHandler, XcodeService, XcodeTool - Extract magic numbers to named constants in ContextBudget - Document magic numbers in RepetitionDetector Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 96871cc commit cc9a48e

11 files changed

Lines changed: 83 additions & 47 deletions

MLX Code/ContentView.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
// Created by MLX Code Generator on 2025-11-18.
66
// Copyright © 2025 Local. All rights reserved.
77
//
8-
// NOTE: This file is deprecated. Use ChatView.swift instead.
8+
// DEPRECATED: This file is no longer used. The main UI entry point is ChatView.swift.
9+
// Retained only for backwards compatibility with any external references.
10+
// Safe to remove once confirmed no launch storyboard or App entry point references it.
911
//
1012

1113
import SwiftUI
1214

13-
/// Legacy content view - replaced by ChatView
14-
/// Kept for backwards compatibility
15+
@available(*, deprecated, message: "Use ChatView instead")
1516
struct ContentView: View {
1617
var body: some View {
1718
Text("This view is deprecated. Use ChatView instead.")

MLX Code/Services/ContextBudget.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ import Foundation
1212

1313
/// Manages token budget allocation across context components
1414
struct ContextBudget {
15+
// MARK: - Budget Allocation Ratios
16+
// These ratios divide the conversation budget (total minus fixed allocations).
17+
// Recent messages get the largest share to preserve conversational context.
18+
// Project context provides file tree / recent file awareness.
19+
// Summary budget holds a compressed summary of older dropped messages.
20+
21+
/// Fraction of conversation budget allocated to recent messages
22+
private static let recentMessagesRatio = 0.7
23+
24+
/// Fraction of conversation budget allocated to project context (file tree, recent files)
25+
private static let projectContextRatio = 0.2
26+
27+
/// Fraction of conversation budget allocated to conversation summary of dropped messages
28+
private static let summaryRatio = 0.1
29+
1530
/// Total token budget (model's context window)
1631
let totalBudget: Int
1732

@@ -31,17 +46,17 @@ struct ContextBudget {
3146

3247
/// Budget for recent messages (70% of conversation budget)
3348
var recentMessagesBudget: Int {
34-
Int(Double(conversationBudget) * 0.7)
49+
Int(Double(conversationBudget) * Self.recentMessagesRatio)
3550
}
3651

37-
/// Budget for project context file tree, recent files (20%)
52+
/// Budget for project context -- file tree, recent files (20%)
3853
var projectContextBudget: Int {
39-
Int(Double(conversationBudget) * 0.2)
54+
Int(Double(conversationBudget) * Self.projectContextRatio)
4055
}
4156

4257
/// Budget for conversation summary of dropped messages (10%)
4358
var summaryBudget: Int {
44-
Int(Double(conversationBudget) * 0.1)
59+
Int(Double(conversationBudget) * Self.summaryRatio)
4560
}
4661

4762
/// Creates a context budget for the given model

MLX Code/Services/MLXService.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ actor MLXService {
152152
}
153153
}
154154

155-
let response = finalResponse!
155+
guard let response = finalResponse else {
156+
throw MLXServiceError.generationFailed("No response received from daemon during model load")
157+
}
156158
await SecureLogger.shared.debug("Received load response - success: \(response.success ?? false), cached: \(response.cached ?? false)", category: "MLXService")
157159

158160
guard response.success == true else {
@@ -1051,7 +1053,7 @@ extension MLXService {
10511053
let homeDir = FileManager.default.homeDirectoryForCurrentUser
10521054
process.currentDirectoryURL = homeDir
10531055

1054-
await SecureLogger.shared.debug("Command: \(pythonPath) \(process.arguments!.joined(separator: " "))", category: "MLXService")
1056+
await SecureLogger.shared.debug("Command: \(pythonPath) \(process.arguments?.joined(separator: " ") ?? "")", category: "MLXService")
10551057
await SecureLogger.shared.debug("Working directory: \(homeDir.path)", category: "MLXService")
10561058

10571059
let outputPipe = Pipe()

MLX Code/Services/MLXSwiftBackend.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ class MLXSwiftBackend: ObservableObject {
5959
isLoading = true
6060
defer { isLoading = false }
6161

62-
// TODO: Replace with native MLX Swift once packages added
63-
// For now, fallback to subprocess
62+
// FALLBACK: Using Python subprocess via mlx_lm.generate CLI.
63+
// Native MLX Swift integration requires adding swift-mlx and mlx-swift-examples
64+
// SPM packages, then replacing this call with direct MLX tensor operations.
65+
// See: https://github.com/ml-explore/mlx-swift
6466
return try await generateViaSubprocess(prompt: prompt, model: model, maxTokens: maxTokens)
6567
}
6668

MLX Code/Services/SlashCommandHandler.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,8 @@ struct SlashCommand: Identifiable {
407407

408408
let task = args.joined(separator: " ")
409409

410-
// TODO: Implement AutonomousAgent
410+
// Agent mode requires: AutonomousAgent class with iterative tool-calling loop,
411+
// task decomposition, and sandboxed execution context. Not yet implemented.
411412
return """
412413
**Agent Mode** (Coming Soon)
413414
@@ -478,7 +479,7 @@ struct SlashCommand: Identifiable {
478479
let xcodeService = XcodeService.shared
479480
try await xcodeService.setProject(path: projectPath)
480481

481-
let scheme = args.count > 1 ? args[1] : ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
482+
let scheme = args.count > 1 ? args[1] : URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
482483

483484
let result = try await xcodeService.fullBuildPipeline(scheme: scheme, configuration: "Release")
484485

@@ -505,7 +506,7 @@ struct SlashCommand: Identifiable {
505506
let xcodeService = XcodeService.shared
506507
try await xcodeService.setProject(path: projectPath)
507508

508-
let scheme = args.count > 1 ? args[1] : ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
509+
let scheme = args.count > 1 ? args[1] : URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
509510
let result = try await xcodeService.archive(scheme: scheme)
510511

511512
return "Archive created: \(result.archivePath)\nVersion: v\(result.version) build \(result.build)"

MLX Code/Services/XcodeService.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,15 @@ actor XcodeService {
828828

829829
/// Finds Info.plist for a project
830830
private func findInfoPlist(projectPath: String) throws -> String {
831-
let projectDir = (projectPath as NSString).deletingLastPathComponent
832-
let projectName = ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
831+
let projectURL = URL(fileURLWithPath: projectPath)
832+
let projectDir = projectURL.deletingLastPathComponent()
833+
let projectName = projectURL.deletingPathExtension().lastPathComponent
833834

834835
// Common locations for Info.plist
835836
let candidates = [
836-
(projectDir as NSString).appendingPathComponent("\(projectName)/Info.plist"),
837-
(projectDir as NSString).appendingPathComponent("Info.plist"),
838-
(projectDir as NSString).appendingPathComponent("\(projectName)/Supporting Files/Info.plist")
837+
projectDir.appendingPathComponent("\(projectName)/Info.plist").path,
838+
projectDir.appendingPathComponent("Info.plist").path,
839+
projectDir.appendingPathComponent("\(projectName)/Supporting Files/Info.plist").path
839840
]
840841

841842
for candidate in candidates {

MLX Code/Tools/EditTool.swift

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,9 @@ actor EditTool {
6363
// Write new content
6464
try newContent.write(toFile: filePath, atomically: true, encoding: .utf8)
6565

66-
// TODO: Record for undo (temporarily disabled due to build issues)
67-
// let operation = FileOperation.edit(
68-
// path: filePath,
69-
// beforeContent: originalContent,
70-
// afterContent: newContent
71-
// )
72-
//
73-
// await MainActor.run {
74-
// FileUndoManager.shared.recordOperation(operation)
75-
// }
66+
// Undo recording disabled: FileUndoManager and FileOperation types were removed
67+
// during a build refactor. Undo support can be re-added by implementing a
68+
// FileUndoManager that stores before/after content keyed by file path.
7669

7770
return EditResult(
7871
success: true,
@@ -113,16 +106,8 @@ actor EditTool {
113106
// Write
114107
try currentContent.write(toFile: filePath, atomically: true, encoding: .utf8)
115108

116-
// TODO: Record undo (temporarily disabled due to build issues)
117-
// let operation = FileOperation.edit(
118-
// path: filePath,
119-
// beforeContent: originalContent,
120-
// afterContent: currentContent
121-
// )
122-
//
123-
// await MainActor.run {
124-
// FileUndoManager.shared.recordOperation(operation)
125-
// }
109+
// Undo recording disabled: FileUndoManager and FileOperation types were removed
110+
// during a build refactor. See single-edit method above for details.
126111

127112
return EditResult(
128113
success: true,

MLX Code/Tools/TestGenerationTool.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class TestGenerationTool: BaseTool {
285285
XCTAssertNotNil(sut)
286286
}
287287
288-
// TODO: Add more test cases
288+
// Additional test methods should be added for each public method in \(className)
289289
}
290290
"""
291291

MLX Code/Tools/XcodeTool.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class XcodeTool: BaseTool {
261261
let xcodeService = XcodeService.shared
262262
try await xcodeService.setProject(path: projectPath)
263263

264-
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
264+
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
265265
let configuration = (try? stringParameter(parameters, key: "configuration")) ?? "Release"
266266

267267
var bumpComponent: VersionComponent?
@@ -304,7 +304,7 @@ class XcodeTool: BaseTool {
304304
let xcodeService = XcodeService.shared
305305
try await xcodeService.setProject(path: projectPath)
306306

307-
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
307+
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
308308

309309
// Archive first
310310
let archiveResult = try await xcodeService.archive(scheme: scheme)
@@ -327,7 +327,7 @@ class XcodeTool: BaseTool {
327327
let xcodeService = XcodeService.shared
328328
try await xcodeService.setProject(path: projectPath)
329329

330-
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
330+
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
331331

332332
let archiveResult = try await xcodeService.archive(scheme: scheme)
333333
let installedPath = try await xcodeService.installToApplications(appPath: archiveResult.appPath)
@@ -340,7 +340,7 @@ class XcodeTool: BaseTool {
340340
let xcodeService = XcodeService.shared
341341
try await xcodeService.setProject(path: projectPath)
342342

343-
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? ((projectPath as NSString).lastPathComponent as NSString).deletingPathExtension
343+
let scheme = (try? stringParameter(parameters, key: "scheme")) ?? URL(fileURLWithPath: projectPath).deletingPathExtension().lastPathComponent
344344

345345
let archiveResult = try await xcodeService.archive(scheme: scheme)
346346
let appName = archiveResult.appName.replacingOccurrences(of: ".app", with: "")

MLX Code/Utilities/RepetitionDetector.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ class RepetitionDetector {
164164

165165
/// Extension to ChatViewModel for repetition detection
166166
extension ChatViewModel {
167-
/// Maximum response length in characters
167+
/// Maximum response length in characters (~4 chars/token * 4096 tokens)
168168
static let maxResponseLength = 16000
169169

170-
/// Maximum response length in tokens (approximate)
170+
/// Maximum response length in tokens (matches typical local model max generation length)
171171
static let maxResponseTokens = 4096
172172
}

0 commit comments

Comments
 (0)