feat(chat): surface failed turns and add error diagnostics to the status report

A turn that OpenCode stopped could end with nothing on screen: the
session.error event was only turned into a sidebar badge, its message was
dropped (the notification expected a different shape than OpenCode sends),
and a send that was accepted but never answered looked the same as success.

- The chat shows what OpenCode reported under the last message while that
  turn is the latest one, and names a user message an idle session has left
  unanswered for five seconds.
- The last 20 session errors are kept in memory and listed in the status
  report (Ctrl/Cmd+Shift+L, also `__opencodeDebug.statusReport()`), next to
  rejected sends, the managed OpenCode process's last error and stderr
  tail, and the OpenCode and desktop log file locations.
- The OpenCode health probe hits /global/health instead of a route that
  does not exist, and probe URLs resolve against the page for web runtimes.
This commit is contained in:
Bohdan Triapitsyn
2026-08-29 23:22:27 +03:00
parent d8e223bf49
commit b18933f19c
21 changed files with 390 additions and 7 deletions
+3
View File
@@ -1553,6 +1553,9 @@ export const dict = {
'header.actions.terminalPanelWithShortcut': 'Terminalpanel ({shortcut})',
'chat.recap.aria': 'Sitzungs-Zusammenfassung',
'chat.recap.label': 'Zusammenfassung:',
'chat.sessionError.title': 'OpenCode hat diese Antwort abgebrochen',
'chat.sessionError.noDetails': 'OpenCode hat keine Details gemeldet. Öffne den Statusbericht (Strg/Cmd+Umschalt+L), um die letzten Fehler zu sehen.',
'chat.sessionError.noReply': 'OpenCode hat keine Antwort auf diese Nachricht begonnen.',
'chat.goal.dialog.titleCreate': 'Sitzungsziel festlegen',
'chat.goal.dialog.titleManage': 'Sitzungsziel',
'chat.goal.dialog.objectiveLabel': 'Ziel',
+3
View File
@@ -1750,6 +1750,9 @@ export const dict = {
'header.actions.terminalPanelWithShortcut': 'Terminal panel ({shortcut})',
'chat.recap.aria': 'Session recap',
'chat.recap.label': 'Recap:',
'chat.sessionError.title': 'OpenCode stopped this reply',
'chat.sessionError.noDetails': 'OpenCode reported no details. Open the status report (Ctrl/Cmd+Shift+L) to see recent errors.',
'chat.sessionError.noReply': 'OpenCode did not start a reply to this message.',
'chat.goal.dialog.titleCreate': 'Set Session Goal',
'chat.goal.dialog.titleManage': 'Session Goal',
'chat.goal.dialog.objectiveLabel': 'Objective',
+3
View File
@@ -1728,6 +1728,9 @@ export const dict: Record<I18nKey, string> = {
"header.actions.terminalPanelWithShortcut": "Panel de terminal ({shortcut})",
"chat.recap.aria": "Resumen de la sesión",
"chat.recap.label": "Resumen:",
"chat.sessionError.title": "OpenCode detuvo esta respuesta",
"chat.sessionError.noDetails": "OpenCode no informó detalles. Abre el informe de estado (Ctrl/Cmd+Mayús+L) para ver los errores recientes.",
"chat.sessionError.noReply": "OpenCode no comenzó una respuesta a este mensaje.",
"chat.goal.dialog.titleCreate": "Definir objetivo de sesión",
"chat.goal.dialog.titleManage": "Objetivo de sesión",
"chat.goal.dialog.objectiveLabel": "Objetivo",
+3
View File
@@ -1507,6 +1507,9 @@ export const dict = {
'header.actions.terminalPanelWithShortcut': 'Panneau à bornes ({shortcut})',
'chat.recap.aria': 'Récapitulatif de la session',
'chat.recap.label': 'Récap :',
'chat.sessionError.title': 'OpenCode a interrompu cette réponse',
'chat.sessionError.noDetails': 'OpenCode n\'a fourni aucun détail. Ouvrez le rapport d\'état (Ctrl/Cmd+Maj+L) pour voir les erreurs récentes.',
'chat.sessionError.noReply': 'OpenCode n\'a pas commencé de réponse à ce message.',
'chat.goal.dialog.titleCreate': 'Définir un objectif de session',
'chat.goal.dialog.titleManage': 'Objectif de session',
'chat.goal.dialog.objectiveLabel': 'Objectif',
+3
View File
@@ -1746,6 +1746,9 @@ export const dict: Record<I18nKey, string> = {
'header.actions.terminalPanelWithShortcut': 'ターミナルパネル({shortcut})',
'chat.recap.aria': 'セッションの要約',
'chat.recap.label': '要約:',
'chat.sessionError.title': 'OpenCode がこの返答を停止しました',
'chat.sessionError.noDetails': 'OpenCode から詳細は報告されませんでした。ステータスレポート(Ctrl/Cmd+Shift+L)で最近のエラーを確認してください。',
'chat.sessionError.noReply': 'OpenCode はこのメッセージへの返答を開始しませんでした。',
'chat.goal.dialog.titleCreate': 'セッションゴールを設定',
'chat.goal.dialog.titleManage': 'セッションゴール',
'chat.goal.dialog.objectiveLabel': '目標',
+3
View File
@@ -1752,6 +1752,9 @@ export const dict: Record<I18nKey, string> = {
'header.actions.terminalPanelWithShortcut': '터미널 패널 ({shortcut})',
'chat.recap.aria': '세션 요약',
'chat.recap.label': '요약:',
'chat.sessionError.title': 'OpenCode가 이 응답을 중단했습니다',
'chat.sessionError.noDetails': 'OpenCode가 세부 정보를 보고하지 않았습니다. 상태 보고서(Ctrl/Cmd+Shift+L)에서 최근 오류를 확인하세요.',
'chat.sessionError.noReply': 'OpenCode가 이 메시지에 대한 응답을 시작하지 않았습니다.',
'chat.goal.dialog.titleCreate': '세션 목표 설정',
'chat.goal.dialog.titleManage': '세션 목표',
'chat.goal.dialog.objectiveLabel': '목표',
+3
View File
@@ -2435,6 +2435,9 @@ export const dict: Record<I18nKey, string> = {
'header.actions.terminalPanelWithShortcut': 'Panel terminala ({shortcut})',
'chat.recap.aria': 'Podsumowanie sesji',
'chat.recap.label': 'Podsumowanie:',
'chat.sessionError.title': 'OpenCode przerwał tę odpowiedź',
'chat.sessionError.noDetails': 'OpenCode nie podał szczegółów. Otwórz raport stanu (Ctrl/Cmd+Shift+L), aby zobaczyć ostatnie błędy.',
'chat.sessionError.noReply': 'OpenCode nie rozpoczął odpowiedzi na tę wiadomość.',
'chat.goal.dialog.titleCreate': 'Ustaw cel sesji',
'chat.goal.dialog.titleManage': 'Cel sesji',
'chat.goal.dialog.objectiveLabel': 'Cel',
@@ -1728,6 +1728,9 @@ export const dict: Record<I18nKey, string> = {
"header.actions.terminalPanelWithShortcut": "Painel de terminal ({shortcut})",
"chat.recap.aria": "Resumo da sessão",
"chat.recap.label": "Resumo:",
"chat.sessionError.title": "O OpenCode interrompeu esta resposta",
"chat.sessionError.noDetails": "O OpenCode não informou detalhes. Abra o relatório de status (Ctrl/Cmd+Shift+L) para ver os erros recentes.",
"chat.sessionError.noReply": "O OpenCode não iniciou uma resposta a esta mensagem.",
"chat.goal.dialog.titleCreate": "Definir objetivo da sessão",
"chat.goal.dialog.titleManage": "Objetivo da sessão",
"chat.goal.dialog.objectiveLabel": "Objetivo",
+3
View File
@@ -1712,6 +1712,9 @@ export const dict = {
'header.actions.terminalPanelWithShortcut': 'Terminal paneli ({shortcut})',
'chat.recap.aria': 'Session özeti',
'chat.recap.label': 'Özet:',
'chat.sessionError.title': 'OpenCode bu yanıtı durdurdu',
'chat.sessionError.noDetails': 'OpenCode ayrıntı bildirmedi. Son hataları görmek için durum raporunu açın (Ctrl/Cmd+Shift+L).',
'chat.sessionError.noReply': 'OpenCode bu mesaja yanıt vermeye başlamadı.',
'chat.goal.dialog.titleCreate': 'Session hedefi belirle',
'chat.goal.dialog.titleManage': 'Session hedefi',
'chat.goal.dialog.objectiveLabel': 'Amaç',
+3
View File
@@ -1728,6 +1728,9 @@ export const dict: Record<I18nKey, string> = {
"header.actions.terminalPanelWithShortcut": "Термінальна панель ({shortcut})",
"chat.recap.aria": "Підсумок сесії",
"chat.recap.label": "Підсумок:",
"chat.sessionError.title": "OpenCode зупинив цю відповідь",
"chat.sessionError.noDetails": "OpenCode не повідомив деталей. Відкрий звіт про стан (Ctrl/Cmd+Shift+L), щоб побачити останні помилки.",
"chat.sessionError.noReply": "OpenCode не почав відповідь на це повідомлення.",
"chat.goal.dialog.titleCreate": "Встановити ціль сесії",
"chat.goal.dialog.titleManage": "Ціль сесії",
"chat.goal.dialog.objectiveLabel": "Ціль",
@@ -1716,6 +1716,9 @@ export const dict: Record<I18nKey, string> = {
'header.actions.terminalPanelWithShortcut': '终端面板({shortcut})',
'chat.recap.aria': '会话回顾',
'chat.recap.label': '回顾:',
'chat.sessionError.title': 'OpenCode 停止了本次回复',
'chat.sessionError.noDetails': 'OpenCode 未报告任何详情。打开状态报告(Ctrl/Cmd+Shift+L)查看最近的错误。',
'chat.sessionError.noReply': 'OpenCode 没有开始回复这条消息。',
'chat.goal.dialog.titleCreate': '设置会话目标',
'chat.goal.dialog.titleManage': '会话目标',
'chat.goal.dialog.objectiveLabel': '目标',
@@ -1720,6 +1720,9 @@ export const dict: Record<I18nKey, string> = {
'header.actions.terminalPanelWithShortcut': '終端機面板({shortcut})',
'chat.recap.aria': '工作階段回顧',
'chat.recap.label': '回顧:',
'chat.sessionError.title': 'OpenCode 停止了本次回覆',
'chat.sessionError.noDetails': 'OpenCode 未回報任何詳情。開啟狀態報告(Ctrl/Cmd+Shift+L)查看最近的錯誤。',
'chat.sessionError.noReply': 'OpenCode 沒有開始回覆這則訊息。',
'chat.goal.dialog.titleCreate': '設定工作階段目標',
'chat.goal.dialog.titleManage': '工作階段目標',
'chat.goal.dialog.objectiveLabel': '目標',