Send notify regression input via workspace socket

This commit is contained in:
Lawrence Chen 2026-03-05 20:18:45 -08:00
parent 6c163b1eb0
commit e6e5a57dd6
3 changed files with 56 additions and 10 deletions

View file

@ -5750,9 +5750,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
"expectedLatestWindowId": window1.windowId.uuidString,
"expectedLatestTabId": tabId1.uuidString,
], at: path)
// Leave the initial window's terminal focused so UI tests can type shell
// commands while still keeping the second window configured for notifications.
window1.window?.makeKeyAndOrderFront(nil)
self.publishMultiWindowNotificationSocketStateIfNeeded(at: path)
}
}
@ -5821,7 +5818,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
"socketPathExists": health.socketPathExists ? "1" : "0",
"socketFailureSignals": failureSignals,
], at: dataPath)
guard !isTimedOut else { return }
guard !isTimedOut, !isReady else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
publish()
}

View file

@ -1247,6 +1247,9 @@ class TerminalController {
case "send_key":
return sendKey(args)
case "send_workspace":
return sendInputToWorkspace(args)
case "send_surface":
return sendInputToSurface(args)
@ -9267,6 +9270,7 @@ class TerminalController {
Input commands:
send <text> - Send text to current terminal
send_key <key> - Send special key (ctrl-c, ctrl-d, enter, tab, escape)
send_workspace <workspace_id> <text> - Send text to a workspace's focused terminal
send_surface <id|idx> <text> - Send text to a specific terminal
send_key_surface <id|idx> <key> - Send special key to a specific terminal
read_screen [id|idx] [--scrollback] [--lines N] - Read terminal text (plain text)
@ -11594,6 +11598,49 @@ class TerminalController {
return success ? "OK" : "ERROR: Failed to send input"
}
private func sendInputToWorkspace(_ args: String) -> String {
guard let tabManager else { return "ERROR: TabManager not available" }
let parts = args.split(separator: " ", maxSplits: 1).map(String.init)
guard parts.count == 2 else { return "ERROR: Usage: send_workspace <workspace_id> <text>" }
let workspaceArg = parts[0].trimmingCharacters(in: .whitespacesAndNewlines)
let text = parts[1]
guard let workspaceId = UUID(uuidString: workspaceArg) else {
return "ERROR: Invalid workspace ID"
}
var success = false
var error: String?
DispatchQueue.main.sync {
guard let targetManager = AppDelegate.shared?.tabManagerFor(tabId: workspaceId)
?? (tabManager.tabs.contains(where: { $0.id == workspaceId }) ? tabManager : nil) else {
error = "ERROR: Workspace not found"
return
}
guard let tab = targetManager.tabs.first(where: { $0.id == workspaceId }),
let terminalPanel = tab.focusedTerminalPanel else {
error = "ERROR: No focused terminal in workspace"
return
}
let unescaped = text
.replacingOccurrences(of: "\\n", with: "\r")
.replacingOccurrences(of: "\\r", with: "\r")
.replacingOccurrences(of: "\\t", with: "\t")
if let surface = terminalPanel.surface.surface {
sendSocketText(unescaped, surface: surface)
} else {
terminalPanel.sendText(unescaped)
terminalPanel.surface.requestBackgroundSurfaceStartIfNeeded()
}
success = true
}
if let error { return error }
return success ? "OK" : "ERROR: Failed to send input"
}
private func sendInputToSurface(_ args: String) -> String {
guard let tabManager = tabManager else { return "ERROR: TabManager not available" }
let parts = args.split(separator: " ", maxSplits: 1).map(String.init)

View file

@ -224,6 +224,10 @@ final class MultiWindowNotificationsUITests: XCTestCase {
XCTFail("Missing setup workspace id")
return
}
guard let tabId1 = setup["tabId1"], !tabId1.isEmpty else {
XCTFail("Missing source workspace id")
return
}
if let expectedSocketPath = setup["socketExpectedPath"], !expectedSocketPath.isEmpty {
socketPath = expectedSocketPath
}
@ -270,11 +274,6 @@ final class MultiWindowNotificationsUITests: XCTestCase {
return
}
XCTAssertTrue(app.windows.element(boundBy: 0).waitForExistence(timeout: 4.0), "Expected at least one window before typing notify command")
app.windows.element(boundBy: 0)
.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5))
.click()
let notifyCommand = [
"rm -f \(shellSingleQuote(commandStatusPath)) \(shellSingleQuote(commandStdoutPath)) \(shellSingleQuote(commandStderrPath));",
"(sleep 1;",
@ -290,7 +289,10 @@ final class MultiWindowNotificationsUITests: XCTestCase {
"2>\(shellSingleQuote(commandStderrPath));",
"printf '%s' $? >\(shellSingleQuote(commandStatusPath))) >/dev/null 2>&1 &"
].joined(separator: " ")
app.typeText(notifyCommand + "\n")
guard socketCommand("send_workspace \(tabId1) \(notifyCommand)\\n") == "OK" else {
XCTFail("Failed to inject delayed bundled `cmux notify` command into source workspace \(tabId1)")
return
}
let finder = XCUIApplication(bundleIdentifier: "com.apple.finder")
finder.activate()