Files
Termind/Frameworks/TermindRemoteInfrastructure/Agent/AgentCommandOutputStream.swift
T
Kaede Akino 7e78bc00c4 feat(agent): unify output truncation and scratch capture
Integrate AgentKit 2.0.1 with shared scratch storage, whole-line tool policies, generated capture paths, and external MCP projection bypass. Update ssh-exec instructions and document the complete tool policy inventory.

Keep compact expansion controls left aligned and display the AgentKit truncation marker above them on both platforms. Cover narrow and wide native layouts, both button states, and marker ordering.
2026-10-17 22:51:26 +08:00

55 lines
1.8 KiB
Swift

import AgentKit
import Foundation
import TermindApplication
/// The SSH pump only enqueues bytes; generic capture, quotas and whole-line
/// selection belong to AgentKit. Both channels share callback-arrival order.
nonisolated public final class AgentCommandOutputStream: @unchecked Sendable {
private let lock = NSLock()
private let accumulator: AgentOutputAccumulator
private var lastReportedAt: ContinuousClock.Instant?
private let interval: Duration
private var report: @Sendable (String, String) -> Void
public init(
interval: Duration = .milliseconds(150),
accumulator: AgentOutputAccumulator,
report: @escaping @Sendable (String, String) -> Void
) {
self.interval = interval
self.accumulator = accumulator
self.report = report
}
public var captureID: UUID { accumulator.id }
public func redirect(to report: @escaping @Sendable (String, String) -> Void) {
lock.withLock {
self.report = report
lastReportedAt = nil
}
report(accumulator.preview, "")
}
public var handler: SSHExecOutputHandler {
{ [self] chunk, _ in append(chunk) }
}
public func snapshot(
envelopeBytes: Int = 0, capturePath: (@Sendable () -> String)? = nil
) async -> AgentOutputAccumulator.Snapshot {
await accumulator.snapshot(envelopeBytes: envelopeBytes, capturePath: capturePath)
}
private func append(_ chunk: Data) {
accumulator.append(chunk)
let due: (@Sendable (String, String) -> Void)? = lock.withLock {
let now = ContinuousClock.now
if let lastReportedAt, now - lastReportedAt < interval { return nil }
lastReportedAt = now
return report
}
if let due { due(accumulator.preview, "") }
}
}