chore: upgrade ktlint to 1.8.0 and format codebase (#1024)
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
3f3b853758
commit
cfe3e736fd
66 files changed
+1287
-541
No files matched your search
@@ -158,7 +158,13 @@ class ChatInputPolicyTest {
|
||||
|
||||
@Test
|
||||
fun applyMention_insertsHandleAndAdvancesCursor() {
|
||||
val initial = TextFieldValue("ask @sc", selection = androidx.compose.ui.text.TextRange(7))
|
||||
val initial =
|
||||
TextFieldValue(
|
||||
"ask @sc",
|
||||
selection =
|
||||
androidx.compose.ui.text
|
||||
.TextRange(7),
|
||||
)
|
||||
val updated = ChatInputPolicy.applyMention(initial, "scout")
|
||||
assertEquals("ask @scout ", updated.text)
|
||||
assertEquals(11, updated.selection.end)
|
||||
|
||||
@@ -369,12 +369,13 @@ class ChatToolDedupeTest {
|
||||
var stream = StreamingState()
|
||||
stream = ChatWsEventReducer.reduce(s, stream, WsEvent.MessageStart("session-1"), "session-1").streamingState
|
||||
stream =
|
||||
ChatWsEventReducer.reduce(
|
||||
s,
|
||||
stream,
|
||||
WsEvent.ReasoningDelta("thinking about meow", "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
ChatWsEventReducer
|
||||
.reduce(
|
||||
s,
|
||||
stream,
|
||||
WsEvent.ReasoningDelta("thinking about meow", "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
var r =
|
||||
ChatWsEventReducer.reduce(
|
||||
s,
|
||||
|
||||
@@ -159,7 +159,12 @@ class ChatUpdateCommandTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
assertTrue("confirm dialog should open", vm.uiState.value.updateConfirmOpen)
|
||||
assertEquals("/update", vm.uiState.value.messages.last().content)
|
||||
assertEquals(
|
||||
"/update",
|
||||
vm.uiState.value.messages
|
||||
.last()
|
||||
.content,
|
||||
)
|
||||
|
||||
// The whole point of the fix: NOTHING goes over the wire.
|
||||
verify(exactly = 0) {
|
||||
|
||||
@@ -513,7 +513,10 @@ class ChatViewModelTest {
|
||||
|
||||
// A blocklisted command can never dispatch — it must not climb
|
||||
// the autocomplete ranking either.
|
||||
assertTrue(viewModel.uiState.value.slashUsageCounts.isEmpty())
|
||||
assertTrue(
|
||||
viewModel.uiState.value.slashUsageCounts
|
||||
.isEmpty(),
|
||||
)
|
||||
verify(exactly = 0) {
|
||||
HermesWsClient.request(WsMethods.COMMAND_DISPATCH, any(), any())
|
||||
}
|
||||
@@ -1033,7 +1036,10 @@ class ChatViewModelTest {
|
||||
viewModel.uiState.value.messages[1]
|
||||
.role,
|
||||
)
|
||||
assertFalse(viewModel.uiState.value.messages[1].isStreaming)
|
||||
assertFalse(
|
||||
viewModel.uiState.value.messages[1]
|
||||
.isStreaming,
|
||||
)
|
||||
assertEquals(
|
||||
MessageRole.TOOL,
|
||||
viewModel.uiState.value.messages[2]
|
||||
@@ -1041,7 +1047,10 @@ class ChatViewModelTest {
|
||||
)
|
||||
assertNull(viewModel.streamingState.value.streamingMessage)
|
||||
assertEquals(
|
||||
listOf(viewModel.uiState.value.messages[1].id),
|
||||
listOf(
|
||||
viewModel.uiState.value.messages[1]
|
||||
.id,
|
||||
),
|
||||
viewModel.streamingState.value.sealedOrphanIds,
|
||||
)
|
||||
|
||||
@@ -1050,7 +1059,8 @@ class ChatViewModelTest {
|
||||
mockEventsFlow.emit(WsEvent.MessageComplete("Calculating sum = 4", sessionId))
|
||||
advanceUntilIdle()
|
||||
val assistant =
|
||||
viewModel.uiState.value.messages.filter { it.role == MessageRole.ASSISTANT }
|
||||
viewModel.uiState.value.messages
|
||||
.filter { it.role == MessageRole.ASSISTANT }
|
||||
assertEquals(2, assistant.size)
|
||||
assertEquals("Calculating sum", assistant[0].content)
|
||||
assertEquals(" = 4", assistant[1].content)
|
||||
@@ -1573,7 +1583,8 @@ class ChatViewModelTest {
|
||||
every { AuthManager.getBaseUrl() } returns "http://test.local/"
|
||||
coEvery { mockApi.getSessions(any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
)
|
||||
coEvery {
|
||||
mockApi.getSessionMessages(
|
||||
@@ -1623,7 +1634,8 @@ class ChatViewModelTest {
|
||||
|
||||
val empty =
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
messagesA.complete(empty)
|
||||
messagesB.complete(empty)
|
||||
@@ -1641,7 +1653,8 @@ class ChatViewModelTest {
|
||||
every { AuthManager.getBaseUrl() } returns "http://test.local/"
|
||||
coEvery { mockApi.getSessions(any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
)
|
||||
coEvery {
|
||||
mockApi.getSessionMessages(
|
||||
@@ -1698,7 +1711,11 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals("session-b", viewModel.uiState.value.currentSessionId)
|
||||
assertEquals(listOf("message-b"), viewModel.uiState.value.messages.map { it.content })
|
||||
assertEquals(
|
||||
listOf("message-b"),
|
||||
viewModel.uiState.value.messages
|
||||
.map { it.content },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1927,7 +1944,8 @@ class ChatViewModelTest {
|
||||
sessionIds.forEach { sessionId ->
|
||||
coEvery { mockApi.getSessionMessages(sessionId, any(), any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1956,7 +1974,11 @@ class ChatViewModelTest {
|
||||
// Warm cache painted and survived the exhausted retry cycle — the
|
||||
// screen never went blank, and the user gets history + an error.
|
||||
assertEquals(1, viewModel.uiState.value.messages.size)
|
||||
assertEquals("Cached hello", viewModel.uiState.value.messages[0].content)
|
||||
assertEquals(
|
||||
"Cached hello",
|
||||
viewModel.uiState.value.messages[0]
|
||||
.content,
|
||||
)
|
||||
assertFalse(viewModel.uiState.value.isLoading)
|
||||
assertNotNull("resumeError must be set after retries exhaust", viewModel.uiState.value.resumeError)
|
||||
assertFalse(viewModel.uiState.value.isResumeRetrying)
|
||||
@@ -2305,7 +2327,8 @@ class ChatViewModelTest {
|
||||
assertEquals("session-new", viewModel.uiState.value.currentSessionId)
|
||||
assertTrue(
|
||||
"recovery notice must be visible",
|
||||
viewModel.uiState.value.messages.any { it.content.contains("no longer available") },
|
||||
viewModel.uiState.value.messages
|
||||
.any { it.content.contains("no longer available") },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2328,7 +2351,8 @@ class ChatViewModelTest {
|
||||
ApiClient.hermesApi.getSessionMessages(capture(fetchedSessions), any(), any(), any(), any())
|
||||
} returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
|
||||
// /fork sends session.branch keyed on the runtime id.
|
||||
@@ -2379,7 +2403,8 @@ class ChatViewModelTest {
|
||||
)
|
||||
} else {
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3301,7 +3326,12 @@ class ChatViewModelTest {
|
||||
assertTrue(viewModel.uiState.value.hasOlderMessages)
|
||||
assertEquals(150, viewModel.uiState.value.messages.size)
|
||||
// Stable keys come from the server row id, not the from-end position.
|
||||
assertEquals("rest-session-456-150", viewModel.uiState.value.messages.last().id)
|
||||
assertEquals(
|
||||
"rest-session-456-150",
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
.id,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3444,7 +3474,10 @@ class ChatViewModelTest {
|
||||
// 160 rows: the 10 new ones appended, the existing 150 kept —
|
||||
// no duplicates, no dropped newest copy (stable row-id keys).
|
||||
assertEquals(160, viewModel.uiState.value.messages.size)
|
||||
assertTrue(viewModel.uiState.value.messages.any { it.id == "rest-session-456-160" })
|
||||
assertTrue(
|
||||
viewModel.uiState.value.messages
|
||||
.any { it.id == "rest-session-456-160" },
|
||||
)
|
||||
}
|
||||
|
||||
// ── Attachment open (issue #724) ─────────────────────────────────────
|
||||
@@ -3506,15 +3539,17 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
val file =
|
||||
java.io.File(System.getProperty("java.io.tmpdir"), "note_${System.nanoTime()}.txt")
|
||||
java.io
|
||||
.File(System.getProperty("java.io.tmpdir"), "note_${System.nanoTime()}.txt")
|
||||
.apply { writeText("downloaded") }
|
||||
coEvery { GatewayFileClient.fetch("/tmp/note.txt", any()) } returns
|
||||
GatewayFileResult.Success(GatewayFile("note.txt", "text/plain", file))
|
||||
@@ -3552,10 +3587,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3590,10 +3626,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3606,7 +3643,8 @@ class ChatViewModelTest {
|
||||
GatewayFile(
|
||||
"report.pdf",
|
||||
"application/pdf",
|
||||
java.io.File(System.getProperty("java.io.tmpdir"), "report_${System.nanoTime()}.pdf")
|
||||
java.io
|
||||
.File(System.getProperty("java.io.tmpdir"), "report_${System.nanoTime()}.pdf")
|
||||
.apply { writeBytes(byteArrayOf(1)) },
|
||||
),
|
||||
)
|
||||
@@ -3625,7 +3663,11 @@ class ChatViewModelTest {
|
||||
|
||||
verify(exactly = 0) { resolver.delete(any(), any(), any()) }
|
||||
assertNull(viewModel.uiState.value.savingAttachmentPath)
|
||||
assertTrue(viewModel.uiState.value.openError.orEmpty().startsWith("Could not save"))
|
||||
assertTrue(
|
||||
viewModel.uiState.value.openError
|
||||
.orEmpty()
|
||||
.startsWith("Could not save"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3633,10 +3675,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3675,10 +3718,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3711,10 +3755,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3743,7 +3788,11 @@ class ChatViewModelTest {
|
||||
|
||||
// …and cleared in all outcomes.
|
||||
assertNull(vm.uiState.value.openingAttachmentPath)
|
||||
assertTrue(vm.uiState.value.openError.orEmpty().contains("big.pdf"))
|
||||
assertTrue(
|
||||
vm.uiState.value.openError
|
||||
.orEmpty()
|
||||
.contains("big.pdf"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3763,7 +3812,10 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
// Optimistic UI state has the user message immediately
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "My super important long prompt" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "My super important long prompt" },
|
||||
)
|
||||
assertTrue(vm.uiState.value.isAgentTyping)
|
||||
// But wsClient.sendMessage not dispatched yet because session_id was null
|
||||
assertTrue(sentPrompts.isEmpty())
|
||||
@@ -3781,7 +3833,10 @@ class ChatViewModelTest {
|
||||
// Prompt should be dispatched automatically!
|
||||
assertEquals(listOf("My super important long prompt"), sentPrompts)
|
||||
assertEquals("session-storage-969", vm.uiState.value.currentSessionId)
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "My super important long prompt" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "My super important long prompt" },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3806,7 +3861,10 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
// Optimistic message in UI
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "Prompt typed during reconnect" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "Prompt typed during reconnect" },
|
||||
)
|
||||
|
||||
// Complete the new SESSION_CREATE RPC
|
||||
mockEventsFlow.emit(
|
||||
@@ -3842,6 +3900,9 @@ class ChatViewModelTest {
|
||||
|
||||
assertFalse(vm.uiState.value.isAgentTyping)
|
||||
assertNotNull(vm.uiState.value.errorMessage)
|
||||
assertTrue(vm.uiState.value.errorMessage!!.contains("Backend exploded"))
|
||||
assertTrue(
|
||||
vm.uiState.value.errorMessage!!
|
||||
.contains("Backend exploded"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -421,7 +421,12 @@ class ChatWsEventReducerTest {
|
||||
)
|
||||
|
||||
assertEquals(1, result.state.messages.size)
|
||||
assertEquals("complete", result.state.messages.single().content)
|
||||
assertEquals(
|
||||
"complete",
|
||||
result.state.messages
|
||||
.single()
|
||||
.content,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -556,12 +561,13 @@ class ChatWsEventReducerTest {
|
||||
var reasoningState = start.streamingState
|
||||
for (token in reasoningTokens) {
|
||||
reasoningState =
|
||||
ChatWsEventReducer.reduce(
|
||||
state,
|
||||
reasoningState,
|
||||
WsEvent.ReasoningDelta(token, "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
ChatWsEventReducer
|
||||
.reduce(
|
||||
state,
|
||||
reasoningState,
|
||||
WsEvent.ReasoningDelta(token, "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
}
|
||||
assertEquals(true, reasoningState.isReasoning)
|
||||
assertEquals("The user just said \"run echo hi\". Let me run it.", reasoningState.reasoningText)
|
||||
@@ -578,8 +584,18 @@ class ChatWsEventReducerTest {
|
||||
"session-1",
|
||||
)
|
||||
assertEquals(1, result.state.messages.size)
|
||||
assertEquals(MessageRole.TOOL, result.state.messages.first().role)
|
||||
assertEquals("terminal", result.state.messages.first().toolName)
|
||||
assertEquals(
|
||||
MessageRole.TOOL,
|
||||
result.state.messages
|
||||
.first()
|
||||
.role,
|
||||
)
|
||||
assertEquals(
|
||||
"terminal",
|
||||
result.state.messages
|
||||
.first()
|
||||
.toolName,
|
||||
)
|
||||
// Issue #771: streaming message + reasoning survive the tool call
|
||||
assertEquals(true, result.streamingState.streamingMessage?.isStreaming)
|
||||
assertEquals("The user just said \"run echo hi\". Let me run it.", result.streamingState.reasoningText)
|
||||
@@ -592,7 +608,12 @@ class ChatWsEventReducerTest {
|
||||
WsEvent.ToolComplete("terminal", mapOf("output" to "hi"), "session-1"),
|
||||
"session-1",
|
||||
)
|
||||
assertEquals(ToolStatus.COMPLETED, result.state.messages.first().toolStatus)
|
||||
assertEquals(
|
||||
ToolStatus.COMPLETED,
|
||||
result.state.messages
|
||||
.first()
|
||||
.toolStatus,
|
||||
)
|
||||
|
||||
// 5. reasoning.available — authoritative full-trace fill
|
||||
val fullReasoning = "The user just said \"run echo hi\". That's a simple terminal command. Let me just run it."
|
||||
@@ -683,7 +704,12 @@ class ChatWsEventReducerTest {
|
||||
"session-1",
|
||||
)
|
||||
|
||||
assertEquals("payload reasoning", result.state.messages.last().reasoningText)
|
||||
assertEquals(
|
||||
"payload reasoning",
|
||||
result.state.messages
|
||||
.last()
|
||||
.reasoningText,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -223,7 +223,8 @@ class SlashCommandDispatchRpcTest {
|
||||
// The optimistic bubble shows the queued TEXT (prefix stripped) so
|
||||
// the transcript sync dedupes it against the server echo.
|
||||
val userBubble =
|
||||
vm.uiState.value.messages.lastOrNull { it.role == MessageRole.USER }
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull { it.role == MessageRole.USER }
|
||||
assertEquals("do the thing", userBubble?.content)
|
||||
}
|
||||
|
||||
@@ -247,7 +248,9 @@ class SlashCommandDispatchRpcTest {
|
||||
vm.sendMessage("/queue")
|
||||
advanceUntilIdle()
|
||||
|
||||
val last = vm.uiState.value.messages.lastOrNull()
|
||||
val last =
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull()
|
||||
assertEquals("usage: /queue <prompt>", last?.content)
|
||||
assertEquals(0, sendCalls)
|
||||
assertTrue(
|
||||
@@ -628,7 +631,9 @@ class SlashCommandDispatchRpcTest {
|
||||
vm.sendMessage("/focus on")
|
||||
advanceUntilIdle()
|
||||
|
||||
val last = vm.uiState.value.messages.lastOrNull()
|
||||
val last =
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull()
|
||||
assertEquals("Focus view: ON (tool progress pinned off)", last?.content)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user