diff --git a/.periphery.yml b/.periphery.yml index 06f14b8f..550b868f 100644 --- a/.periphery.yml +++ b/.periphery.yml @@ -1,5 +1,6 @@ project: Termind.xcodeproj retain_public: true schemes: -- Termind +- TFM +- TFI - TermindMCPBridge diff --git a/Frameworks/TermindApplication/Agent/CommandGeneratorService.swift b/Frameworks/TermindApplication/Agent/CommandGeneratorService.swift index acf52e93..f836ab53 100644 --- a/Frameworks/TermindApplication/Agent/CommandGeneratorService.swift +++ b/Frameworks/TermindApplication/Agent/CommandGeneratorService.swift @@ -107,11 +107,6 @@ public final class CommandGeneratorController: CommandGenerating { self.service = CommandGeneratorService() } - init(ai: AIConfigurationModel, service: CommandGeneratorService) { - self.ai = ai - self.service = service - } - /// A local readiness check for contextual UI. It never contacts a model; /// it only resolves the configured role and its already local credential. public var isLocallyAvailable: Bool { diff --git a/Frameworks/TermindApplication/FeatureModels/PortForwardingEditorPolicy.swift b/Frameworks/TermindApplication/FeatureModels/PortForwardingEditorPolicy.swift index 95983f0a..ba7901b7 100644 --- a/Frameworks/TermindApplication/FeatureModels/PortForwardingEditorPolicy.swift +++ b/Frameworks/TermindApplication/FeatureModels/PortForwardingEditorPolicy.swift @@ -15,7 +15,7 @@ public nonisolated struct PortForwardingEditorPolicy { public var isWaitingForSave: Bool { isEnabled && !hasSavedConfiguration && !isRuntimeActive } public init( - rule: PortForwardingRule?, host: Host, + rule: PortForwardingRule?, savedRule: PortForwardingRule?, savedHost: Host?, isEnabled: Bool, isRuntimeActive: Bool ) { diff --git a/Frameworks/TermindApplication/RepositoryChange.swift b/Frameworks/TermindApplication/RepositoryChange.swift index 6e5ff1ac..8e458cc1 100644 --- a/Frameworks/TermindApplication/RepositoryChange.swift +++ b/Frameworks/TermindApplication/RepositoryChange.swift @@ -1,5 +1,4 @@ import Foundation -import TermindDomain public nonisolated enum RepositoryChangeReason: String, Hashable, Sendable { case initial diff --git a/Frameworks/TermindApplication/SessionReconnectController.swift b/Frameworks/TermindApplication/SessionReconnectController.swift index 951b8142..23b75502 100644 --- a/Frameworks/TermindApplication/SessionReconnectController.swift +++ b/Frameworks/TermindApplication/SessionReconnectController.swift @@ -1,5 +1,4 @@ import Foundation -import TermindDomain public nonisolated struct ReconnectPolicy: Sendable, Equatable { public static let sessionDefault = ReconnectPolicy() diff --git a/Frameworks/TermindApplication/Speech/SpeechTranscription.swift b/Frameworks/TermindApplication/Speech/SpeechTranscription.swift index 6b8a61e7..dfda6136 100644 --- a/Frameworks/TermindApplication/Speech/SpeechTranscription.swift +++ b/Frameworks/TermindApplication/Speech/SpeechTranscription.swift @@ -197,13 +197,13 @@ public final class SpeechTranscriptionCoordinator { case .partial(let transcript): latestPartial = transcript case .final(let transcript): - finish(with: transcript, ownerID: ownerID) + finish(with: transcript) case .failure(let failure): fail(failure, for: ownerID) } } - private func finish(with transcript: String, ownerID: UUID) { + private func finish(with transcript: String) { let cleaned = transcript.trimmingCharacters(in: .whitespacesAndNewlines) guard !cleaned.isEmpty else { resetSession(cancelService: true) diff --git a/Frameworks/TermindInfrastructure/Speech/SpeechAudioInput.swift b/Frameworks/TermindInfrastructure/Speech/SpeechAudioInput.swift index adff4e21..876fe5a1 100644 --- a/Frameworks/TermindInfrastructure/Speech/SpeechAudioInput.swift +++ b/Frameworks/TermindInfrastructure/Speech/SpeechAudioInput.swift @@ -1,5 +1,4 @@ @preconcurrency import AVFoundation -import TermindApplication public typealias SpeechAudioBufferHandler = @Sendable (AVAudioPCMBuffer) -> Void public typealias SpeechAudioLevelHandler = @Sendable (Float) -> Void diff --git a/Frameworks/TermindPersistence/AISecretStore.swift b/Frameworks/TermindPersistence/AISecretStore.swift index e09e6f97..123b7dec 100644 --- a/Frameworks/TermindPersistence/AISecretStore.swift +++ b/Frameworks/TermindPersistence/AISecretStore.swift @@ -1,6 +1,5 @@ import Foundation import SwiftData -import TermindDomain @Model public final class PersistentAISecretLocation { diff --git a/Frameworks/TermindPersistence/AgentPersistence.swift b/Frameworks/TermindPersistence/AgentPersistence.swift index d03f18b6..7e09fbc1 100644 --- a/Frameworks/TermindPersistence/AgentPersistence.swift +++ b/Frameworks/TermindPersistence/AgentPersistence.swift @@ -1,7 +1,6 @@ import AgentKit import Foundation import SwiftData -import TermindDomain @Model public final class PersistentAgentConversation { diff --git a/Frameworks/TermindPersistence/SettingsSyncJournalStore.swift b/Frameworks/TermindPersistence/SettingsSyncJournalStore.swift index 1274fafa..eb95458d 100644 --- a/Frameworks/TermindPersistence/SettingsSyncJournalStore.swift +++ b/Frameworks/TermindPersistence/SettingsSyncJournalStore.swift @@ -1,6 +1,5 @@ import Foundation import SwiftData -import TermindApplication import TermindDomain public nonisolated struct SettingsRemoteMerge: Sendable { diff --git a/Frameworks/TermindPersistence/SkillPersistence.swift b/Frameworks/TermindPersistence/SkillPersistence.swift index c706911a..e729ca00 100644 --- a/Frameworks/TermindPersistence/SkillPersistence.swift +++ b/Frameworks/TermindPersistence/SkillPersistence.swift @@ -1,7 +1,6 @@ import AgentKit import Foundation import SwiftData -import TermindDomain @Model public final class PersistentAgentSkill { diff --git a/Frameworks/TermindPresentation/AssistantContextGauge.swift b/Frameworks/TermindPresentation/AssistantContextGauge.swift index c0764b8a..5a57540c 100644 --- a/Frameworks/TermindPresentation/AssistantContextGauge.swift +++ b/Frameworks/TermindPresentation/AssistantContextGauge.swift @@ -1,6 +1,5 @@ import AgentKit import SwiftUI -import TermindApplication /// How full the model's context window is, as a ring. /// diff --git a/Frameworks/TermindPresentation/ChatMessageTimestampFormatter.swift b/Frameworks/TermindPresentation/ChatMessageTimestampFormatter.swift index 5b5a1ebc..e6be5cca 100644 --- a/Frameworks/TermindPresentation/ChatMessageTimestampFormatter.swift +++ b/Frameworks/TermindPresentation/ChatMessageTimestampFormatter.swift @@ -1,5 +1,4 @@ import Foundation -import TermindApplication nonisolated public enum ChatMessageTimestampFormatter { public static func string( diff --git a/Frameworks/TermindPresentation/MetricsDiskTable.swift b/Frameworks/TermindPresentation/MetricsDiskTable.swift index 1903610d..f47b2c8a 100644 --- a/Frameworks/TermindPresentation/MetricsDiskTable.swift +++ b/Frameworks/TermindPresentation/MetricsDiskTable.swift @@ -1,5 +1,4 @@ import SwiftUI -import TermindApplication import TermindDomain /// A fixed label gutter followed by four equal-width, leading-aligned data columns. diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBackgroundCommands.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBackgroundCommands.swift index 06111150..824a5e2e 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBackgroundCommands.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBackgroundCommands.swift @@ -1,6 +1,5 @@ import Foundation import TermindApplication -import TermindInfrastructure /// What a command looks like to whoever asked about it. /// @@ -75,8 +74,6 @@ public actor AgentBackgroundCommands { public static let defaultIdleTimeout = Duration.seconds(600) private struct Entry { - let hostID: UUID - let command: String let stream: AgentCommandOutputStream let task: Task let session: any SSHExecSessionProtocol @@ -103,15 +100,12 @@ public actor AgentBackgroundCommands { /// Takes ownership of a command still in flight, and of the session it is /// running on. public func adopt( - hostID: UUID, command: String, stream: AgentCommandOutputStream, + stream: AgentCommandOutputStream, task: Task, session: any SSHExecSessionProtocol, now: ContinuousClock.Instant = .now ) -> UUID { let handle = UUID() - entries[handle] = Entry( - hostID: hostID, command: command, stream: stream, task: task, - session: session, lastAskedAt: now - ) + entries[handle] = Entry(stream: stream, task: task, session: session, lastAskedAt: now) startSweeping() return handle } diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSFTPTools.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSFTPTools.swift index 8944c0b5..787d7455 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSFTPTools.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSFTPTools.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import TermindApplication import TermindDomain -import TermindInfrastructure import struct TermindDomain.Host diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSSHTools.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSSHTools.swift index 1bb49cb5..238006e8 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSSHTools.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentBuiltInSSHTools.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import TermindApplication import TermindDomain -import TermindInfrastructure nonisolated public struct ListHostsTool: AgentToolDefinition, AgentToolSchemaBuilding { public static let presenter = AgentToolDetailPresenter( @@ -440,8 +439,7 @@ nonisolated public struct SSHExecTool: AgentToolDefinition, AgentToolSchemaBuild // fresh one. await pool.detachExec(hostID: hostID, session: session) let handle = await background.adopt( - hostID: hostID, command: command, stream: stream, - task: running, session: session + stream: stream, task: running, session: session ) let captured = stream.captured return Self.result( diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentCommandOutputStream.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentCommandOutputStream.swift index b04c2013..68c4a69e 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentCommandOutputStream.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentCommandOutputStream.swift @@ -1,6 +1,5 @@ import Foundation import TermindApplication -import TermindInfrastructure /// Turns the chunks a running command emits into progress reports. /// diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift index f875926c..b1af15de 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import TermindApplication import TermindDomain -import TermindInfrastructure import struct TermindDomain.Host @@ -306,7 +305,6 @@ public final class AgentHostResolver: Sendable { } private struct AuthenticationRequirement { - var host: Host var mode: AgentSSHAuthenticationRequest.Mode } @@ -321,32 +319,32 @@ public final class AgentHostResolver: Sendable { store.key(keyID)?.requiresPassphraseEntry == true, submission.passphrase?.isEmpty != false { - return AuthenticationRequirement(host: host, mode: .passphrase(keyID: keyID)) + return AuthenticationRequirement(mode: .passphrase(keyID: keyID)) } if submission.username.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || (submission.keyID == nil && submission.password == nil) { - return AuthenticationRequirement(host: host, mode: .identity) + return AuthenticationRequirement(mode: .identity) } if forcedHostID == host.id { - return AuthenticationRequirement(host: host, mode: .identity) + return AuthenticationRequirement(mode: .identity) } return nil } guard let identity = store.identity(for: host) else { - return AuthenticationRequirement(host: host, mode: .identity) + return AuthenticationRequirement(mode: .identity) } let resolution = store.sshCredentials(for: identity) if let keyID = resolution.requiredPassphraseKeyID { - return AuthenticationRequirement(host: host, mode: .passphrase(keyID: keyID)) + return AuthenticationRequirement(mode: .passphrase(keyID: keyID)) } if identity.username.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || resolution.credentials.isEmpty { - return AuthenticationRequirement(host: host, mode: .identity) + return AuthenticationRequirement(mode: .identity) } if forcedHostID == host.id { - return AuthenticationRequirement(host: host, mode: .identity) + return AuthenticationRequirement(mode: .identity) } return nil } diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/AgentScratchTransferTools.swift b/Frameworks/TermindRemoteInfrastructure/Agent/AgentScratchTransferTools.swift index 6d1e63f8..59077852 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/AgentScratchTransferTools.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/AgentScratchTransferTools.swift @@ -1,7 +1,6 @@ import AgentKit import Foundation import TermindApplication -import TermindInfrastructure // The two scratch tools that touch a host. // diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/GetMetricsTool.swift b/Frameworks/TermindRemoteInfrastructure/Agent/GetMetricsTool.swift index 33a0d25a..cb64282a 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/GetMetricsTool.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/GetMetricsTool.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import TermindApplication import TermindDomain -import TermindInfrastructure import struct TermindDomain.Host diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/MetricsToolOutput.swift b/Frameworks/TermindRemoteInfrastructure/Agent/MetricsToolOutput.swift index 2a8a4642..c4b422d8 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/MetricsToolOutput.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/MetricsToolOutput.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import TermindApplication import TermindDomain -import TermindInfrastructure /// The wire projection stays with the tool; monitoring has no dependency on AgentKit. nonisolated public enum MetricsToolOutput { diff --git a/Frameworks/TermindRemoteInfrastructure/Agent/TermindAgentTools.swift b/Frameworks/TermindRemoteInfrastructure/Agent/TermindAgentTools.swift index 84af4164..2cccb1b1 100644 --- a/Frameworks/TermindRemoteInfrastructure/Agent/TermindAgentTools.swift +++ b/Frameworks/TermindRemoteInfrastructure/Agent/TermindAgentTools.swift @@ -1,7 +1,6 @@ import AgentKit import Foundation import TermindApplication -import TermindInfrastructure /// What Termind's own agent tools are built from. /// diff --git a/Frameworks/TermindRemoteInfrastructure/SSH/SSHKeyMaterial.swift b/Frameworks/TermindRemoteInfrastructure/SSH/SSHKeyMaterial.swift index cf608c52..cd6eabcc 100644 --- a/Frameworks/TermindRemoteInfrastructure/SSH/SSHKeyMaterial.swift +++ b/Frameworks/TermindRemoteInfrastructure/SSH/SSHKeyMaterial.swift @@ -2,7 +2,6 @@ import CSSH2 import CryptoKit import Foundation import OpenSSL -import TermindApplication import TermindDomain public nonisolated enum SSHKeyMaterialError: LocalizedError { diff --git a/Memory/REFACTOR.md b/Memory/REFACTOR.md index 89d90060..3072e0e0 100644 --- a/Memory/REFACTOR.md +++ b/Memory/REFACTOR.md @@ -1325,3 +1325,42 @@ remains behind the context menu and confirmation dialog. **Action:** Move platform-neutral presentation into TermindPresentation, inject tool presenters from the existing registry, and retain native platform rendering and viewport ownership. Replace mobile disclosure and detail branches with shared policy consumers. Estimated duplicate-policy reduction: 150–250 lines, with desktop presentation code moved rather than copied. **Verification:** Pending shared, desktop, mobile and bilingual rendering checks. + +## 2026-09-12 — Remove Periphery-confirmed dead code + +**Status:** Completed on 2026-09-12; both app builds, focused tests, formatting, and localization checks pass. + +**Evidence:** Periphery 3.8.0 reported 461 diagnostics while indexing the TFM scheme and 73 while indexing TFI. +After excluding test-only diagnostics and reconciling the two platform scans, source-reference checks confirm 34 +unused production imports, several uncalled private/internal helpers and compatibility accessors, and stored fields +that are written but never read. SwiftUI/AppKit lifecycle entry points, Codable payload fields, C callback parameters, +protocol witnesses, and fields whose synthesized conformance reads are intentionally excluded from this pass. + +**Action:** Repair the stale Periphery scheme configuration, remove only declarations confirmed by both index data +and `rg`, then rerun both app builds, focused tests for changed behavior, strict formatting, localization validation, +and Periphery to measure the reduced result set. + +**Estimated reduction:** 70–110 production lines without adding an abstraction. + +**Result:** Removed 34 unused production imports, three empty source files, and confirmed dead initializers, +accessors, view helpers, state storage, and background-command metadata. Production code changed by net -150 lines. +The TFM production diagnostic count fell from 114 to 69 (461 to 416 including test diagnostics), while the TFI +production count fell from 66 to 41. Remaining reports are retained protocol/C callback parameters, synthesized +conformance or Codable fields, dynamic UI entry points, and separate candidates that require their own behavioral +review. The macOS and iOS builds pass, as do 49 focused Agent background command, port forwarding, and speech tests, +strict Swift formatting, Simplified Chinese localization validation, and `git diff --check`. + +## 2026-09-12 — Remove UI implementation-type assertions + +**Status:** Completed. + +**Evidence:** `TranscriptListViewBridgeTests` directly asserts dedicated concrete row classes, the mobile Terminal +list suite reflects private SwiftUI/ListViewKit view types, and the macOS Host chooser render test additionally +requires an `NSTableView`. Existing behavior tests already cover rendering, row identity and reuse, dynamic type, +virtualization, interaction, and state isolation without requiring those implementation choices. + +**Action:** Remove the two tests whose only result is a concrete UI type, drop their test-only helper, and keep the +Host chooser environment/rendering coverage without asserting its underlying AppKit table class. Preserve UI type +access that is required to exercise or observe actual interaction behavior. + +**Estimated reduction:** 30–40 test lines with no production or public API changes. diff --git a/TFI/App/MobileRuntimeVersions.swift b/TFI/App/MobileRuntimeVersions.swift index 8668db55..ec80bcc6 100644 --- a/TFI/App/MobileRuntimeVersions.swift +++ b/TFI/App/MobileRuntimeVersions.swift @@ -1,5 +1,4 @@ import GhosttyKit -import TermindInfrastructure import TermindRemoteInfrastructure nonisolated enum MobileRuntimeVersions { diff --git a/TFI/Application/Agent/MobileAssistantModel.swift b/TFI/Application/Agent/MobileAssistantModel.swift index 02bd89b6..41213abe 100644 --- a/TFI/Application/Agent/MobileAssistantModel.swift +++ b/TFI/Application/Agent/MobileAssistantModel.swift @@ -125,8 +125,6 @@ final class MobileAssistantModel { } } - func stop() { for conversation in store.conversations { conversation.stop() } } - func suspendRecording() { speech.cancelAll() } func expireBackground() { diff --git a/TFI/Application/FeatureModels/MobileMCPEditorModel.swift b/TFI/Application/FeatureModels/MobileMCPEditorModel.swift index 73a60685..0d2744f8 100644 --- a/TFI/Application/FeatureModels/MobileMCPEditorModel.swift +++ b/TFI/Application/FeatureModels/MobileMCPEditorModel.swift @@ -2,7 +2,6 @@ import AgentKit import Foundation import Observation import TermindApplication -import TermindDomain @MainActor @Observable final class MobileMCPEditorModel { @@ -36,7 +35,6 @@ final class MobileMCPEditorModel { self.discover = discover key.begin(in: ai, reference: server.credentialRef) } - var isDirty: Bool { draft != original || key.isDirty } var hasValidURL: Bool { guard let url = URL(string: draft.url.trimmingCharacters(in: .whitespacesAndNewlines)), let scheme = url.scheme?.lowercased(), let host = url.host, !host.isEmpty diff --git a/TFI/Features/AI/MobileAssistantConversation.swift b/TFI/Features/AI/MobileAssistantConversation.swift index d1087248..dc67fe39 100644 --- a/TFI/Features/AI/MobileAssistantConversation.swift +++ b/TFI/Features/AI/MobileAssistantConversation.swift @@ -4,7 +4,6 @@ import SwiftUI import TermindApplication import TermindDomain import TermindPresentation -import TermindRemoteInfrastructure import UniformTypeIdentifiers private struct MobileConversationAttachmentDropModifier: ViewModifier { diff --git a/TFI/Features/Assistant/MobileAssistantView.swift b/TFI/Features/Assistant/MobileAssistantView.swift index 9d99aabc..a856d875 100644 --- a/TFI/Features/Assistant/MobileAssistantView.swift +++ b/TFI/Features/Assistant/MobileAssistantView.swift @@ -1,7 +1,6 @@ import AgentKit import SwiftUI import TermindApplication -import TermindDomain enum MobileAssistantLibraryRoute: String, Identifiable, Hashable { case conversations diff --git a/TFI/Features/HostEditor/MobileHostEditor.swift b/TFI/Features/HostEditor/MobileHostEditor.swift index 4c1908e9..57e59ebd 100644 --- a/TFI/Features/HostEditor/MobileHostEditor.swift +++ b/TFI/Features/HostEditor/MobileHostEditor.swift @@ -133,7 +133,7 @@ struct MobileHostEditor: View { for rule: PortForwardingRule, runtimeIsActive: Bool ) -> PortForwardingEditorPolicy { PortForwardingEditorPolicy( - rule: rule, host: draft, + rule: rule, savedRule: app.forwardingLibrary.portForwarding(rule.id), savedHost: library.host(draft.id), isEnabled: app.forwardings.isEnabled(rule.id), isRuntimeActive: runtimeIsActive) } diff --git a/TFI/Features/Ports/MobileForwardingEditor.swift b/TFI/Features/Ports/MobileForwardingEditor.swift index 9d0c28d8..366c16a4 100644 --- a/TFI/Features/Ports/MobileForwardingEditor.swift +++ b/TFI/Features/Ports/MobileForwardingEditor.swift @@ -57,7 +57,7 @@ struct MobileForwardingEditor: View { private var state: PortForwardingEditorPolicy { PortForwardingEditorPolicy( - rule: draft, host: host, + rule: draft, savedRule: app.forwardingLibrary.portForwarding(draft.id), savedHost: app.library.host(host.id), isEnabled: app.forwardings.isEnabled(draft.id), isRuntimeActive: runtime.isActive) } diff --git a/TFI/Features/SFTP/MobileRemoteFileEditor.swift b/TFI/Features/SFTP/MobileRemoteFileEditor.swift index d15b9e5a..c8d50bdb 100644 --- a/TFI/Features/SFTP/MobileRemoteFileEditor.swift +++ b/TFI/Features/SFTP/MobileRemoteFileEditor.swift @@ -1,7 +1,6 @@ import SwiftUI import TermindDomain import TermindPresentation -import TermindRemoteInfrastructure struct MobileRemoteFileEditor: View { enum Mode { case rename, permissions } diff --git a/TFI/Features/Workspaces/MobileWorkspace.swift b/TFI/Features/Workspaces/MobileWorkspace.swift index 7b2d55d1..a9480016 100644 --- a/TFI/Features/Workspaces/MobileWorkspace.swift +++ b/TFI/Features/Workspaces/MobileWorkspace.swift @@ -4,7 +4,6 @@ import GhosttyTerminal import Observation import TermindApplication import TermindDomain -import TermindInfrastructure import TermindPresentation import TermindRemoteInfrastructure import UIKit @@ -129,7 +128,6 @@ final class MobileWorkspace: Identifiable { private let connection: RemoteSessionConnectionController private var viewport = InMemoryTerminalViewport(columns: 80, rows: 24) - var uploadConflictCount: Int { pendingUpload?.batch.conflictCount ?? 0 } var transferConflictCount: Int { pendingRemoteCopy?.batch.conflictCount ?? pendingDownload?.batch.conflictCount diff --git a/TFI/Features/Workspaces/MobileWorkspaceDescriptor.swift b/TFI/Features/Workspaces/MobileWorkspaceDescriptor.swift index b733ec46..7cdab0f8 100644 --- a/TFI/Features/Workspaces/MobileWorkspaceDescriptor.swift +++ b/TFI/Features/Workspaces/MobileWorkspaceDescriptor.swift @@ -3,7 +3,6 @@ import Foundation nonisolated struct MobileWorkspaceDescriptor: Hashable, Identifiable, Sendable { enum Kind: String, CaseIterable, Sendable { case ssh, sftp - var title: String { self == .ssh ? "SSH" : "SFTP" } var symbol: String { self == .ssh ? "terminal" : "folder" } } diff --git a/TFITests/MobileTerminalListTests.swift b/TFITests/MobileTerminalListTests.swift index 96d65a3c..cf501a2d 100644 --- a/TFITests/MobileTerminalListTests.swift +++ b/TFITests/MobileTerminalListTests.swift @@ -8,26 +8,6 @@ import UIKit @Suite(.serialized) @MainActor struct MobileTerminalListTests { - @Test func snippetsAndHistoryMountNativeSwiftUILists() async throws { - let app = try MobileAppModel(inMemory: true) - let host = TermindDomain.Host(name: "Test", host: "example.invalid") - app.library.upsert(host) - app.library.upsert(Snippet(title: "List files", body: "ls -la\npwd")) - app.commandHistory.record("pwd", for: host.id) - let workspace = MobileWorkspace( - descriptor: MobileWorkspaceDescriptor(hostID: host.id, title: host.name, kind: .ssh), - hosts: app.library, - commandHistory: app.commandHistory) - - try await withHostedView(MobileTerminalSnippetsView(library: app.library, workspace: workspace)) { root in - expectNativeList(in: root.view) - } - - try await withHostedView(MobileCommandHistoryView(workspace: workspace)) { root in - expectNativeList(in: root.view) - } - } - @Test func deletingAnEndpointUpdatesTheNativeHistoryList() async throws { let app = try MobileAppModel(inMemory: true) let host = TermindDomain.Host(name: "Test", host: "example.invalid") @@ -152,15 +132,6 @@ struct MobileTerminalListTests { try await check(controller) } - private func expectNativeList(in root: UIView) { - let legacyList = descendants(of: UIScrollView.self, in: root).first { - String(reflecting: type(of: $0)).contains("ListViewKit.ListView") - } - #expect(legacyList == nil) - #expect(descendants(of: MobileHostingListRow.self, in: root).isEmpty) - #expect(!nativeVisibleCells(in: root).isEmpty) - } - private func nativeVisibleCells(in root: UIView) -> [UIView] { let collectionCells = descendants(of: UICollectionViewCell.self, in: root) let tableCells = descendants(of: UITableViewCell.self, in: root) diff --git a/TFM/App/DesktopSettingsKey.swift b/TFM/App/DesktopSettingsKey.swift index b0815f6b..7e039a6e 100644 --- a/TFM/App/DesktopSettingsKey.swift +++ b/TFM/App/DesktopSettingsKey.swift @@ -60,23 +60,4 @@ nonisolated enum DesktopSettingsKey { } /// The last approval posture selected in the Assistant composer. static let agentPermissionMode = "assistant.permissionMode" - static var isWebSearchEnabled: Bool { - UserDefaults.standard.object(forKey: SettingsKey.webSearchEnabled) as? Bool - ?? SettingsKey.defaultWebSearchEnabled - } - /// Let a provider run the search on its own servers where it can. - /// - /// On by default, because where it works it beats a snippet API: the - /// provider reads whole pages and the model simply knows things. Off is the - /// compatibility position — every model then goes through the backend - /// below, which behaves identically on every endpoint. - /// - /// The switch exists because whether a given endpoint really runs the - /// search is a *guess*: `ModelProvider.supportsNativeWebSearch(model:)` - /// infers it from the model id, and a gateway can make that inference wrong - /// in either direction. This is the escape hatch for when it is. - static var isBuiltInWebSearchEnabled: Bool { - UserDefaults.standard.object(forKey: SettingsKey.webSearchBuiltIn) as? Bool - ?? SettingsKey.defaultWebSearchBuiltIn - } } diff --git a/TFM/App/RuntimeVersions.swift b/TFM/App/RuntimeVersions.swift index 1ae56f4d..54443c7c 100644 --- a/TFM/App/RuntimeVersions.swift +++ b/TFM/App/RuntimeVersions.swift @@ -1,5 +1,4 @@ import GhosttyKit -import TermindInfrastructure import TermindRemoteInfrastructure nonisolated enum RuntimeVersions { diff --git a/TFM/Application/Agent/TermindAgentPresentation.swift b/TFM/Application/Agent/TermindAgentPresentation.swift deleted file mode 100644 index 656f5599..00000000 --- a/TFM/Application/Agent/TermindAgentPresentation.swift +++ /dev/null @@ -1 +0,0 @@ -import TermindApplication diff --git a/TFM/Features/AI/CommandCardView.swift b/TFM/Features/AI/CommandCardView.swift index 84181569..3ed6059b 100644 --- a/TFM/Features/AI/CommandCardView.swift +++ b/TFM/Features/AI/CommandCardView.swift @@ -1,5 +1,4 @@ import SwiftUI -import TermindApplication import TermindDomain extension CommandRisk { diff --git a/TFM/Features/AI/ContextAttachmentOpener.swift b/TFM/Features/AI/ContextAttachmentOpener.swift index 4d063dbb..73971a17 100644 --- a/TFM/Features/AI/ContextAttachmentOpener.swift +++ b/TFM/Features/AI/ContextAttachmentOpener.swift @@ -1,7 +1,6 @@ import AgentKit import AppKit import Foundation -import TermindApplication import UniformTypeIdentifiers nonisolated enum ContextAttachmentOpener { diff --git a/TFM/Features/AI/MarkdownBlockListView.swift b/TFM/Features/AI/MarkdownBlockListView.swift index 9319c38e..6108d109 100644 --- a/TFM/Features/AI/MarkdownBlockListView.swift +++ b/TFM/Features/AI/MarkdownBlockListView.swift @@ -3,7 +3,6 @@ import Combine import MarkdownParser import MarkdownView import SwiftUI -import TermindApplication import TermindPresentation /// The Markdown entry point used by the transcript. diff --git a/TFM/Features/AI/MarkdownCodeBlockView.swift b/TFM/Features/AI/MarkdownCodeBlockView.swift index d35e696e..c9409dde 100644 --- a/TFM/Features/AI/MarkdownCodeBlockView.swift +++ b/TFM/Features/AI/MarkdownCodeBlockView.swift @@ -1,5 +1,4 @@ import SwiftUI -import TermindApplication import TermindDomain /// The one fenced block Termind owns instead of MarkdownView: a shell command diff --git a/TFM/Features/Ports/PortForwardingEditorState.swift b/TFM/Features/Ports/PortForwardingEditorState.swift index d22dd0ea..7bf42152 100644 --- a/TFM/Features/Ports/PortForwardingEditorState.swift +++ b/TFM/Features/Ports/PortForwardingEditorState.swift @@ -22,7 +22,7 @@ struct PortForwardingEditorState { isEnabled: Bool, runtime: PortForwardingRuntimeState ) { let shared = PortForwardingEditorPolicy( - rule: rule, host: host, savedRule: savedRule, savedHost: savedHost, + rule: rule, savedRule: savedRule, savedHost: savedHost, isEnabled: isEnabled, isRuntimeActive: runtime.isActive) hasSavedConfiguration = shared.hasSavedConfiguration self.isEnabled = shared.isEnabled diff --git a/TFM/Features/Settings/ModelProviderEditorSheet.swift b/TFM/Features/Settings/ModelProviderEditorSheet.swift index 583ff54c..1866860c 100644 --- a/TFM/Features/Settings/ModelProviderEditorSheet.swift +++ b/TFM/Features/Settings/ModelProviderEditorSheet.swift @@ -158,27 +158,10 @@ struct ModelProviderEditorPage: View { app.aiConfiguration.upsert(provider) } - // MARK: - Binding - private var endpoint: ProviderEndpoint { app.aiConfiguration.endpoint(for: modelProviderID) } - /// A two-way binding into the endpoint, written through the store's one - /// derivation so the composed URL and the API format are updated together. - private func endpointBinding( - _ keyPath: WritableKeyPath - ) -> Binding { - Binding( - get: { endpoint[keyPath: keyPath] }, - set: { newValue in - var updated = endpoint - updated[keyPath: keyPath] = newValue - app.aiConfiguration.setEndpoint(updated, for: modelProviderID) - } - ) - } - /// A two-way binding into the stored provider. /// /// Reads and writes go through `AIConfigurationModel` rather than through a local copy, diff --git a/TFM/Features/Settings/SettingsPageView.swift b/TFM/Features/Settings/SettingsPageView.swift index 18097d9b..24b9e893 100644 --- a/TFM/Features/Settings/SettingsPageView.swift +++ b/TFM/Features/Settings/SettingsPageView.swift @@ -638,8 +638,6 @@ private struct TerminalSettings: View { @Environment(AppModel.self) private var app private var fontSize: Double { app.terminalSettings.preferences.fontSize } private var fontFollowTheme: Bool { app.terminalSettings.preferences.fontFollowTheme } - private var shellIntegration: Bool { app.terminalSettings.preferences.shellIntegration } - private var remoteWindowTitleInMenuBar: Bool { app.terminalSettings.preferences.remoteWindowTitleInMenuBar } private var darkTheme: String { app.terminalSettings.preferences.darkTheme } private var lightTheme: String { app.terminalSettings.preferences.lightTheme } private var darkCustomEnabled: Bool { app.terminalSettings.preferences.darkCustomEnabled } diff --git a/TFM/Features/Settings/TerminalCustomConfigurationEditorSheet.swift b/TFM/Features/Settings/TerminalCustomConfigurationEditorSheet.swift index 2e7ff163..0fb07b9c 100644 --- a/TFM/Features/Settings/TerminalCustomConfigurationEditorSheet.swift +++ b/TFM/Features/Settings/TerminalCustomConfigurationEditorSheet.swift @@ -9,13 +9,6 @@ nonisolated enum TerminalCustomConfigurationScheme: String, Identifiable, Hashab var id: String { rawValue } - var settingsKey: String { - switch self { - case .light: SettingsKey.terminalCustomConfigurationLight - case .dark: SettingsKey.terminalCustomConfigurationDark - } - } - var preferenceKeyPath: WritableKeyPath { switch self { case .light: \.lightCustomConfiguration diff --git a/TFM/Features/StatusBar/StatusBarView.swift b/TFM/Features/StatusBar/StatusBarView.swift index bc4ccde9..4328e635 100644 --- a/TFM/Features/StatusBar/StatusBarView.swift +++ b/TFM/Features/StatusBar/StatusBarView.swift @@ -242,10 +242,6 @@ struct StatusBarView: View { private var host: Host? { pane?.hostID.flatMap { app.hostLibrary.host($0) } } - private func item(_ symbol: String, _ text: String) -> some View { - Label(text, systemImage: symbol).truncationMode(.head) - } - private func workingDirectoryButton(_ path: String, displayed: String) -> some View { Button { app.onboarding.recordUse(of: .statusBarPath) diff --git a/TFM/Infrastructure/Database/ModelContext+Commit.swift b/TFM/Infrastructure/Database/ModelContext+Commit.swift index 5ad5345f..de2cbbc5 100644 --- a/TFM/Infrastructure/Database/ModelContext+Commit.swift +++ b/TFM/Infrastructure/Database/ModelContext+Commit.swift @@ -2,10 +2,6 @@ import SwiftData @MainActor extension ModelContext { - func savePendingChanges() throws { - try commit {} - } - func commit(_ operation: () throws -> Void) throws { do { try operation() diff --git a/TFM/Infrastructure/Networking/LoopbackHTTPServer.swift b/TFM/Infrastructure/Networking/LoopbackHTTPServer.swift index bc0d82a7..2734da52 100644 --- a/TFM/Infrastructure/Networking/LoopbackHTTPServer.swift +++ b/TFM/Infrastructure/Networking/LoopbackHTTPServer.swift @@ -64,7 +64,6 @@ actor LoopbackHTTPServer { private var handler: Handler? private var stateHandler: StateHandler? private var readyListeners = 0 - private(set) var state: State = .stopped func start( port: UInt16, token: String, @@ -78,7 +77,6 @@ actor LoopbackHTTPServer { self.token = token self.handler = handler self.stateHandler = stateHandler - state = .starting stateHandler(.starting) do { @@ -125,7 +123,6 @@ actor LoopbackHTTPServer { connections.removeAll() handler = nil readyListeners = 0 - state = .stopped stateHandler?(.stopped) stateHandler = nil } @@ -135,11 +132,9 @@ actor LoopbackHTTPServer { case .ready: readyListeners += 1 if readyListeners == listeners.count { - state = .ready(port: port) stateHandler?(.ready(port: port)) } case .failed(let error): - state = .failed(error.localizedDescription) stateHandler?(.failed(error.localizedDescription)) for listener in listeners { listener.cancel() } default: diff --git a/TFM/Infrastructure/Repositories/PersistentModelFactories.swift b/TFM/Infrastructure/Repositories/PersistentModelFactories.swift index 84af06a2..87dd42f2 100644 --- a/TFM/Infrastructure/Repositories/PersistentModelFactories.swift +++ b/TFM/Infrastructure/Repositories/PersistentModelFactories.swift @@ -31,15 +31,3 @@ extension AIConfigurationModel { ) } } - -extension SkillLibraryModel { - convenience init( - modelContext: ModelContext, - seedDefaults: UserDefaults = .standard - ) { - self.init( - persistence: SkillPersistence(context: modelContext), - seedDefaults: seedDefaults - ) - } -} diff --git a/TFM/Infrastructure/SSH/DispatchQueue+Async.swift b/TFM/Infrastructure/SSH/DispatchQueue+Async.swift deleted file mode 100644 index 3ddf39b4..00000000 --- a/TFM/Infrastructure/SSH/DispatchQueue+Async.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation - -extension DispatchQueue { - func perform( - _ operation: @escaping @Sendable () throws -> T - ) async throws -> T { - try await withCheckedThrowingContinuation { continuation in - async { - do { continuation.resume(returning: try operation()) } catch { continuation.resume(throwing: error) } - } - } - } - - func perform(_ operation: @escaping @Sendable () -> Void) async { - await withCheckedContinuation { continuation in - async { - operation() - continuation.resume() - } - } - } -} diff --git a/TFM/Infrastructure/Security/AISecretStore+Desktop.swift b/TFM/Infrastructure/Security/AISecretStore+Desktop.swift deleted file mode 100644 index 61065e2a..00000000 --- a/TFM/Infrastructure/Security/AISecretStore+Desktop.swift +++ /dev/null @@ -1,7 +0,0 @@ -import SwiftData -import TermindPersistence -import TermindRemoteInfrastructure - -extension AISecretStore { - convenience init(context: ModelContext) { self.init(context: context, keychain: KeychainSecretStore()) } -} diff --git a/TFM/Infrastructure/Security/KeychainSecretStore+Desktop.swift b/TFM/Infrastructure/Security/KeychainSecretStore+Desktop.swift index 32af65f3..84ef9f16 100644 --- a/TFM/Infrastructure/Security/KeychainSecretStore+Desktop.swift +++ b/TFM/Infrastructure/Security/KeychainSecretStore+Desktop.swift @@ -1,4 +1,3 @@ -import TermindInfrastructure import TermindRemoteInfrastructure extension KeychainSecretStore { diff --git a/TFMTests/AgentBackgroundCommandTests.swift b/TFMTests/AgentBackgroundCommandTests.swift index 27ab64ac..99df8e54 100644 --- a/TFMTests/AgentBackgroundCommandTests.swift +++ b/TFMTests/AgentBackgroundCommandTests.swift @@ -103,7 +103,7 @@ struct AgentBackgroundCommandTests { let commands = AgentBackgroundCommands(sweepInterval: nil) let session = StubSession() let handle = await commands.adopt( - hostID: UUID(), command: "make", stream: AgentCommandOutputStream { _, _ in }, + stream: AgentCommandOutputStream { _, _ in }, task: Task { exited(0, stdout: "built") }, session: session ) @@ -126,7 +126,7 @@ struct AgentBackgroundCommandTests { let released = AsyncRelease() let stream = AgentCommandOutputStream(interval: .zero) { _, _ in } let handle = await commands.adopt( - hostID: UUID(), command: "deploy", stream: stream, + stream: stream, task: Task { await released.wait() return exited(0) @@ -160,7 +160,7 @@ struct AgentBackgroundCommandTests { let released = AsyncRelease() let stream = AgentCommandOutputStream(interval: .zero) { _, _ in } let handle = await commands.adopt( - hostID: UUID(), command: "deploy", stream: stream, + stream: stream, task: Task { await released.wait() return exited(0) @@ -184,7 +184,7 @@ struct AgentBackgroundCommandTests { let released = AsyncRelease() let start = ContinuousClock.now let stale = await commands.adopt( - hostID: UUID(), command: "tail -f", stream: AgentCommandOutputStream { _, _ in }, + stream: AgentCommandOutputStream { _, _ in }, task: Task { await released.wait() return exited(0) @@ -192,7 +192,7 @@ struct AgentBackgroundCommandTests { now: start ) _ = await commands.adopt( - hostID: UUID(), command: "deploy", stream: AgentCommandOutputStream { _, _ in }, + stream: AgentCommandOutputStream { _, _ in }, task: Task { await released.wait() return exited(0) @@ -221,7 +221,7 @@ struct AgentBackgroundCommandTests { let session = StubSession() let released = AsyncRelease() _ = await commands.adopt( - hostID: UUID(), command: "tail -f", stream: AgentCommandOutputStream { _, _ in }, + stream: AgentCommandOutputStream { _, _ in }, task: Task { await released.wait() return exited(0) @@ -253,7 +253,7 @@ struct AgentBackgroundCommandTests { return exited(0) } let handle = await commands.adopt( - hostID: UUID(), command: "deploy", stream: AgentCommandOutputStream { _, _ in }, + stream: AgentCommandOutputStream { _, _ in }, task: task, session: StubSession() ) diff --git a/TFMTests/ArchitectureBoundaryTests.swift b/TFMTests/ArchitectureBoundaryTests.swift index c6381d01..9ca6e1d6 100644 --- a/TFMTests/ArchitectureBoundaryTests.swift +++ b/TFMTests/ArchitectureBoundaryTests.swift @@ -511,85 +511,6 @@ struct ArchitectureBoundaryTests { } } - @Test - func mobileNavigationAndMetricsShareTheDesktopDesign() throws { - let root = try String( - contentsOf: sourceRoot.appending(path: "../TFI/App/MobileRootView.swift"), encoding: .utf8) - #expect(!root.contains("Welcome")) - #expect(root.contains("Label(\"Transfers\", systemImage: \"arrow.up.arrow.down\")")) - let vault = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Vault/MobileVaultView.swift"), encoding: .utf8) - let navigation = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Shell/MobileNavigation.swift"), encoding: .utf8) - #expect(navigation.contains("case vault, metrics, workspaces, assistant, settings")) - #expect(!vault.contains("Label(\"Port Forwarding\", systemImage:")) - #expect(vault.contains("open(host.id, .ssh)")) - let cards = try String( - contentsOf: sourceRoot.appending(path: "../TFI/UI/Managed/MobileCards.swift"), encoding: .utf8) - #expect(vault.contains("MobileActionCard {")) - #expect(cards.contains(".contextMenu {")) - #expect(cards.contains("actions")) - #expect(!vault.contains("Import SSH Files")) - let keys = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Keychain/MobileCredentialsView.swift"), - encoding: .utf8) - #expect(!keys.contains("draft.notes")) - let settings = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Settings/MobileSettingsView.swift"), encoding: .utf8 - ) - #expect(settings.contains("Label(\"App\", systemImage: \"app.badge\")")) - #expect(settings.contains("Label(\"Sync\", systemImage: \"icloud\")")) - #expect(!settings.contains("Live Activities")) - let mobile = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Application/Metrics/MobileMetricsModel.swift"), - encoding: .utf8) - #expect(mobile.contains("ServerMetricsModel(")) - #expect(!mobile.contains("while !Task.isCancelled")) - let workspace = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Workspaces/MobileWorkspaceView.swift"), - encoding: .utf8) - #expect(workspace.contains(".toolbarTitleMenu")) - #expect(!workspace.contains("connectionMenuAction")) - #expect(workspace.contains("let closeWorkspace: (UUID) -> Void")) - #expect(workspace.contains("closeWorkspace(workspace.id)")) - #expect(workspace.contains("MobileOverflowMenuLabel(\"More\")")) - #expect(workspace.contains("Button(\"Generate Command\", systemImage: \"sparkles\")")) - let snippets = try #require(workspace.range(of: "Button(\"Snippets\", systemImage: \"curlybraces\")")) - let history = try #require(workspace.range(of: "Button(\"History\", systemImage: \"clock\")")) - let historyDivider = try #require(workspace[history.upperBound...].range(of: "Divider()")) - let nextMatch = try #require(workspace.range(of: "Button(\"Next Match\", systemImage: \"chevron.down\")")) - #expect(snippets.lowerBound < history.lowerBound) - #expect(history.lowerBound < historyDivider.lowerBound) - #expect(historyDivider.lowerBound < nextMatch.lowerBound) - #expect(workspace.contains(".dropDestination(for: URL.self)")) - #expect(workspace.contains(".toolbar(.hidden, for: .tabBar)")) - #expect(workspace.contains("guard let text = UIPasteboard.general.string else { return }")) - #expect(workspace.contains("workspace.insertTerminalText(text)")) - let mobileScene = try String( - contentsOf: sourceRoot.appending(path: "../TFI/App/MobileSceneModel.swift"), encoding: .utf8) - let mobileCommands = try String( - contentsOf: sourceRoot.appending(path: "../TFI/App/MobileCommands.swift"), encoding: .utf8) - #expect(root.contains(".focusedSceneValue(\\.mobileScene, scene)")) - #expect(mobileScene.contains("func closeWorkspace(_ id: MobileWorkspace.ID)")) - #expect(mobileCommands.contains("@FocusedValue(\\.mobileScene)")) - #expect(!workspace.contains("Circle().fill(workspace.connected")) - let keyboard = try String( - contentsOf: sourceRoot.appending(path: "../TFI/Features/Terminal/MobileTerminalKeyboard.swift"), - encoding: .utf8) - #expect(keyboard.contains("ScrollView(.horizontal")) - let pasteButton = try #require(keyboard.range(of: "pasteButton")) - let keyboardToggle = try #require(keyboard.range(of: "keyboardToggle")) - #expect(pasteButton.lowerBound < keyboardToggle.lowerBound) - #expect(keyboard.contains("Button(action: paste)")) - #expect(keyboard.contains("Label(\"Paste\", systemImage: \"doc.on.clipboard\")")) - #expect(keyboard.contains(".padding(.horizontal, 8)")) - #expect(keyboard.contains("static let barHeight: CGFloat = 44")) - #expect(keyboard.contains(".buttonStyle(.plain)")) - #expect(!keyboard.contains(".buttonStyle(.bordered)")) - #expect(keyboard.contains(".frame(width: 44, height: 44)")) - #expect(keyboard.contains(".frame(height: Self.barHeight)")) - } - @Test func mobilePortUsesSharedStoresAndSeparateSigningFiles() throws { let mobile = try String( diff --git a/TFMTests/MetricsInteractionTests.swift b/TFMTests/MetricsInteractionTests.swift index 1f2aba1d..79bc8cbd 100644 --- a/TFMTests/MetricsInteractionTests.swift +++ b/TFMTests/MetricsInteractionTests.swift @@ -47,7 +47,7 @@ struct MetricsInteractionTests { } @Test(arguments: [HostChooserPurpose.connect, .batchStartup, .metrics]) - func hostChoosersMountNativeListsWithTheirRequiredEnvironment( + func hostChoosersRenderWithTheirRequiredEnvironment( purpose: HostChooserPurpose ) async throws { let host = Host(name: "Fixture", host: "fixture.invalid") @@ -68,7 +68,6 @@ struct MetricsInteractionTests { try await Task.sleep(for: .milliseconds(100)) hosting.layoutSubtreeIfNeeded() #expect(hosting.fittingSize.height > 0) - #expect(hasTable(hosting)) #expect(windowModel.workspaces.isEmpty) #expect(app.serverMetrics.servers.isEmpty) } diff --git a/TFMTests/TranscriptListViewTests.swift b/TFMTests/TranscriptListViewTests.swift index 8e3a8a6c..5c47adc3 100644 --- a/TFMTests/TranscriptListViewTests.swift +++ b/TFMTests/TranscriptListViewTests.swift @@ -352,21 +352,6 @@ struct TranscriptListViewBridgeTests { #expect(!presentation.disclosures.hasPendingAutoCollapse(id)) } - @Test - func entryKindsUseDedicatedReusableRowTypes() { - let coordinator = TranscriptListView.Coordinator() - let listView = coordinator.makeListView() - let empty = TranscriptEntry(id: UUID(), content: .empty) - let assistant = assistant(id: UUID(), text: "Hello") - listView.frame = CGRect(x: 0, y: 0, width: 420, height: 800) - - update(coordinator, listView, entries: [empty, assistant]) - listView.layoutSubtreeIfNeeded() - - #expect(listView.rowView(for: empty.id) is TranscriptEmptyRow) - #expect(listView.rowView(for: assistant.id) is TranscriptAssistantRow) - } - @Test func streamingUpdateKeepsTheMountedAssistantRowIdentity() throws { let coordinator = TranscriptListView.Coordinator() diff --git a/WorkspaceActivitySupport/WorkspaceActivityAttributes.swift b/WorkspaceActivitySupport/WorkspaceActivityAttributes.swift index 7fe5cab8..342db1e2 100644 --- a/WorkspaceActivitySupport/WorkspaceActivityAttributes.swift +++ b/WorkspaceActivitySupport/WorkspaceActivityAttributes.swift @@ -10,7 +10,6 @@ nonisolated struct WorkspaceActivityAttributes: ActivityAttributes { var connected: Bool var iconAsset: String? = nil - var symbol: String { "server.rack" } var destinationURL: URL { WorkspaceActivityAttributes.destinationURL(for: id) } }