tide-commander 1.147.1 → 1.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +6 -3
  3. package/dist/assets/BossLogsModal-Cs4kWugD.js +1 -0
  4. package/dist/assets/BossSpawnModal-BudMgJqj.js +1 -0
  5. package/dist/assets/ControlsModal-Bh6_3qtH.js +1 -0
  6. package/dist/assets/DockerLogsModal-Nf4wQFfz.js +2 -0
  7. package/dist/assets/{EmbeddedEditor-DfM3SrO7.js → EmbeddedEditor-BfRXRX50.js} +1 -1
  8. package/dist/assets/{GmailOAuthSetup-DBWs7uzU.js → GmailOAuthSetup-CXUtjA0r.js} +1 -1
  9. package/dist/assets/{GoogleOAuthSetup-yQjT5QzU.js → GoogleOAuthSetup-D-_rwicD.js} +1 -1
  10. package/dist/assets/{IframeModal-DUTIyP5I.js → IframeModal-CdaXsQK0.js} +1 -1
  11. package/dist/assets/{IntegrationsPanel-DPURuiaz.js → IntegrationsPanel-ZsSVxcWr.js} +2 -2
  12. package/dist/assets/{LogViewerModal-CDZvTdfO.js → LogViewerModal-BAf-klB2.js} +1 -1
  13. package/dist/assets/{MonitoringModal-Dq2EJgbH.js → MonitoringModal-BjRbh5z4.js} +1 -1
  14. package/dist/assets/{PM2LogsModal-C3dlYlGv.js → PM2LogsModal-SaywDZVL.js} +2 -2
  15. package/dist/assets/{RestoreArchivedAreaModal-BMFk0G8D.js → RestoreArchivedAreaModal-jru2Ez9a.js} +1 -1
  16. package/dist/assets/Scene2DCanvas-NJHoe2Qg.js +1 -0
  17. package/dist/assets/SceneManager-i9wVMa_V.js +104 -0
  18. package/dist/assets/{SkillsPanel-D326VBDa.js → SkillsPanel-BHfKLzWe.js} +3 -3
  19. package/dist/assets/{SlackMultiInstanceSetup-CA4nm925.js → SlackMultiInstanceSetup-BfVevCSo.js} +1 -1
  20. package/dist/assets/SpawnModal-29x5z53B.js +1 -0
  21. package/dist/assets/{StatisticsModal-BUpvkJXA.js → StatisticsModal-MbIByjWD.js} +1 -1
  22. package/dist/assets/{SubordinateAssignmentModal-DtVsKDqV.js → SubordinateAssignmentModal-DF0vYaM6.js} +1 -1
  23. package/dist/assets/{TriggerManagerPanel-OD14xVMw.js → TriggerManagerPanel-EGcKS1Pt.js} +1 -1
  24. package/dist/assets/{WorkflowEditorPanel-B4UF3rcS.js → WorkflowEditorPanel-BLmejfqe.js} +1 -1
  25. package/dist/assets/{area-logos-Uc9SAeYg.js → area-logos-C4fgpLgO.js} +1 -1
  26. package/dist/assets/grok.ico +0 -0
  27. package/dist/assets/grok.png +0 -0
  28. package/dist/assets/{index-xBtKu0I8.js → index-B-2H7O_Y.js} +2 -2
  29. package/dist/assets/{index-CuHJm43U.js → index-B9xpLAcH.js} +1 -1
  30. package/dist/assets/index-BZ4wZwRu.js +19 -0
  31. package/dist/assets/index-BiiLWTXJ.js +1 -0
  32. package/dist/assets/{index-BC3Y_BAQ.js → index-C6Kf4ewu.js} +5 -5
  33. package/dist/assets/index-C8CGfmXP.js +1 -0
  34. package/dist/assets/index-DThK5_yS.js +5 -0
  35. package/dist/assets/index-DYgVP0G3.js +2 -0
  36. package/dist/assets/index-DhD3m2Qx.js +1 -0
  37. package/dist/assets/main-B0UlZnfk.js +260 -0
  38. package/dist/assets/main-DeiAIdzy.css +1 -0
  39. package/dist/assets/{web-DlzqHyn8.js → web-CXC8P25z.js} +1 -1
  40. package/dist/assets/{web-B-xc0c6e.js → web-LGEDa25c.js} +1 -1
  41. package/dist/assets/{web-BuDeKWBN.js → web-NM4dUqWg.js} +1 -1
  42. package/dist/index.html +2 -2
  43. package/dist/locales/de/tools.json +3 -1
  44. package/dist/locales/en/tools.json +7 -3
  45. package/dist/locales/es/tools.json +3 -1
  46. package/dist/locales/fr/tools.json +4 -2
  47. package/dist/locales/hi/tools.json +4 -2
  48. package/dist/locales/it/tools.json +19 -17
  49. package/dist/locales/ja/tools.json +4 -2
  50. package/dist/locales/pt/tools.json +3 -1
  51. package/dist/locales/ru/tools.json +3 -1
  52. package/dist/locales/zh-CN/tools.json +3 -1
  53. package/dist/src/packages/server/claude/runner/process-lifecycle.js +53 -0
  54. package/dist/src/packages/server/claude/runner/stdout-pipeline.js +125 -4
  55. package/dist/src/packages/server/claude/runner/watchdog.js +12 -0
  56. package/dist/src/packages/server/claude/session-loader.js +280 -0
  57. package/dist/src/packages/server/data/index.js +1 -0
  58. package/dist/src/packages/server/grok/backend.js +231 -0
  59. package/dist/src/packages/server/grok/index.js +4 -0
  60. package/dist/src/packages/server/grok/json-event-parser.js +138 -0
  61. package/dist/src/packages/server/grok/session-watcher.js +460 -0
  62. package/dist/src/packages/server/routes/agents.js +7 -2
  63. package/dist/src/packages/server/runtime/grok-runtime-provider.js +11 -0
  64. package/dist/src/packages/server/runtime/index.js +1 -0
  65. package/dist/src/packages/server/services/agent-service.js +26 -5
  66. package/dist/src/packages/server/services/runtime-command-execution.js +4 -2
  67. package/dist/src/packages/server/services/runtime-events.js +46 -7
  68. package/dist/src/packages/server/services/runtime-service.js +19 -3
  69. package/dist/src/packages/server/utils/tool-formatting.js +40 -12
  70. package/dist/src/packages/server/websocket/handlers/agent-handler.js +70 -17
  71. package/dist/src/packages/server/websocket/listeners/runtime-listeners.js +63 -7
  72. package/dist/src/packages/shared/agent-types.js +10 -0
  73. package/package.json +1 -1
  74. package/dist/assets/BossLogsModal-Cn8IVdqn.js +0 -1
  75. package/dist/assets/BossSpawnModal-Don-RZyh.js +0 -1
  76. package/dist/assets/ControlsModal-C9--xWPi.js +0 -1
  77. package/dist/assets/DockerLogsModal-DSGnpfm5.js +0 -2
  78. package/dist/assets/Scene2DCanvas-DlumJCbl.js +0 -1
  79. package/dist/assets/SceneManager-UnhMFja8.js +0 -104
  80. package/dist/assets/SpawnModal-B1QOjZPe.js +0 -1
  81. package/dist/assets/index-BD6swoQU.js +0 -19
  82. package/dist/assets/index-C4mf6B5U.js +0 -1
  83. package/dist/assets/index-COHImd74.js +0 -1
  84. package/dist/assets/index-CScFEdm8.js +0 -1
  85. package/dist/assets/index-CmmpVZ8w.js +0 -2
  86. package/dist/assets/index-DkDzXtdj.js +0 -5
  87. package/dist/assets/main-Bp6V_-sL.js +0 -256
  88. package/dist/assets/main-ijcbyjBn.css +0 -1
@@ -1 +1 @@
1
- import{c$ as s}from"./main-Bp6V_-sL.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
1
+ import{dc as s}from"./main-B0UlZnfk.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
@@ -1 +1 @@
1
- import{c$ as t}from"./main-Bp6V_-sL.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
1
+ import{dc as t}from"./main-B0UlZnfk.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
@@ -1 +1 @@
1
- import{c$ as a}from"./main-Bp6V_-sL.js";import{ImpactStyle as i,NotificationType as r}from"./index-xBtKu0I8.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
1
+ import{dc as a}from"./main-B0UlZnfk.js";import{ImpactStyle as i,NotificationType as r}from"./index-B-2H7O_Y.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
package/dist/index.html CHANGED
@@ -22,10 +22,10 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main-Bp6V_-sL.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-B0UlZnfk.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
28
- <link rel="stylesheet" crossorigin href="/assets/main-ijcbyjBn.css">
28
+ <link rel="stylesheet" crossorigin href="/assets/main-DeiAIdzy.css">
29
29
  </head>
30
30
  <body>
31
31
  <div id="app"></div>
@@ -45,7 +45,9 @@
45
45
  "listFiles": "Dateien auflisten",
46
46
  "searchFiles": "Dateien durchsuchen",
47
47
  "executeCommand": "Befehl ausführen"
48
- }
48
+ },
49
+ "showOutputsInline": "Alle Bash-Ausgaben inline anzeigen",
50
+ "hideOutputsInline": "Inline-Bash-Ausgaben ausblenden"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Nachrichteninfo",
@@ -43,13 +43,17 @@
43
43
  "askFollowupQuestion": "AskFollowupQuestion",
44
44
  "askUserQuestion": "AskUserQuestion",
45
45
  "attemptCompletion": "AttemptCompletion",
46
- "listFiles": "ListFiles",
47
- "searchFiles": "SearchFiles",
46
+ "listFiles": "List Files",
47
+ "searchFiles": "Search Files",
48
48
  "executeCommand": "ExecuteCommand",
49
49
  "spawnAgent": "Spawn Agent",
50
50
  "sendInput": "Send Input",
51
+ "sendMessage": "Message Agent",
52
+ "taskOutput": "Task Output",
51
53
  "wait": "Wait"
52
- }
54
+ },
55
+ "showOutputsInline": "Show all bash outputs inline",
56
+ "hideOutputsInline": "Hide inline bash outputs"
53
57
  },
54
58
  "metadata": {
55
59
  "messageInfo": "Message Info",
@@ -45,7 +45,9 @@
45
45
  "listFiles": "Listar archivos",
46
46
  "searchFiles": "Buscar archivos",
47
47
  "executeCommand": "Ejecutar comando"
48
- }
48
+ },
49
+ "showOutputsInline": "Mostrar todos los outputs de bash en línea",
50
+ "hideOutputsInline": "Ocultar los outputs de bash en línea"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Info del mensaje",
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "Afficher toutes les sorties bash en ligne",
50
+ "hideOutputsInline": "Masquer les sorties bash en ligne"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Infos du message",
@@ -272,4 +274,4 @@
272
274
  "noContent": "Aucun contenu de réponse disponible.",
273
275
  "rawMarkdown": "Markdown brut"
274
276
  }
275
- }
277
+ }
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "सभी bash आउटपुट इनलाइन दिखाएँ",
50
+ "hideOutputsInline": "इनलाइन bash आउटपुट छिपाएँ"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "संदेश जानकारी",
@@ -272,4 +274,4 @@
272
274
  "noContent": "कोई प्रतिक्रिया सामग्री उपलब्ध नहीं।",
273
275
  "rawMarkdown": "रॉ Markdown"
274
276
  }
275
- }
277
+ }
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "Mostra tutti gli output bash in linea",
50
+ "hideOutputsInline": "Nascondi gli output bash in linea"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Info messaggio",
@@ -85,7 +87,7 @@
85
87
  "builtIn": "Integrata",
86
88
  "notAssigned": "Non assegnata",
87
89
  "noSkillsDefined": "Nessuna skill definita ancora",
88
- "createSkillsHint": "Crea skill per insegnare agli agenti capacit\u00e0 specifiche",
90
+ "createSkillsHint": "Crea skill per insegnare agli agenti capacità specifiche",
89
91
  "noCustomClasses": "Nessuna classe agente personalizzata ancora",
90
92
  "createClassesHint": "Crea classi personalizzate con skill predefinite associate",
91
93
  "noClassesMatch": "Nessuna classe corrisponde a \"{{query}}\"",
@@ -121,7 +123,7 @@
121
123
  "uploading": "Caricamento...",
122
124
  "createClass": "Crea classe",
123
125
  "viewBuiltInSkill": "Visualizza skill integrata",
124
- "builtInNotice": "Questa \u00e8 una skill integrata di Tide Commander. Il contenuto non pu\u00f2 essere modificato, ma puoi cambiare a quali agenti e classi \u00e8 assegnata.",
126
+ "builtInNotice": "Questa è una skill integrata di Tide Commander. Il contenuto non può essere modificato, ma puoi cambiare a quali agenti e classi è assegnata.",
125
127
  "nameRequired": "Nome *",
126
128
  "slugLabel": "Slug",
127
129
  "slugHint": "Identificativo URL-safe (generato automaticamente)",
@@ -138,8 +140,8 @@
138
140
  "disabledSkillsHint": "Le skill disabilitate non saranno disponibili per gli agenti",
139
141
  "saveAssignments": "Salva assegnazioni",
140
142
  "createSkill": "Crea skill",
141
- "deleteSkillConfirm": "Eliminare questa skill? Questa azione non pu\u00f2 essere annullata.",
142
- "updateSkillConfirm": "L'aggiornamento di questa skill riavvier\u00e0 tutti gli agenti che la utilizzano.\n\nDovrai riprendere manualmente gli agenti che stavano lavorando.\n\nContinuare?",
143
+ "deleteSkillConfirm": "Eliminare questa skill? Questa azione non può essere annullata.",
144
+ "updateSkillConfirm": "L'aggiornamento di questa skill riavvierà tutti gli agenti che la utilizzano.\n\nDovrai riprendere manualmente gli agenti che stavano lavorando.\n\nContinuare?",
143
145
  "deleteClassConfirm": "Sei sicuro di voler eliminare questa classe agente personalizzata?",
144
146
  "classCount": "{{count}} classi",
145
147
  "agentCount": "{{count}} agente/i",
@@ -164,7 +166,7 @@
164
166
  "classScout": "Scout",
165
167
  "classScoutDesc": "Esplorazione del codebase",
166
168
  "classBuilder": "Builder",
167
- "classBuilderDesc": "Implementazione funzionalit\u00e0",
169
+ "classBuilderDesc": "Implementazione funzionalità",
168
170
  "classDebugger": "Debugger",
169
171
  "classDebuggerDesc": "Ricerca e correzione bug",
170
172
  "classArchitect": "Architetto",
@@ -196,7 +198,7 @@
196
198
  "customToolPlaceholder": "Strumento personalizzato (es. Bash(make:*))"
197
199
  },
198
200
  "subagent": {
199
- "subagentTask": "Attivit\u00e0 sottoagente",
201
+ "subagentTask": "Attività sottoagente",
200
202
  "spawned": "Generato",
201
203
  "completed": "Completato",
202
204
  "duration": "Durata"
@@ -223,24 +225,24 @@
223
225
  "replaceAll": "Sostituisci tutto"
224
226
  },
225
227
  "todoList": {
226
- "title": "Lista attivit\u00e0"
228
+ "title": "Lista attività"
227
229
  },
228
230
  "bossContext": {
229
231
  "teamContext": "Contesto team",
230
232
  "injectedInstructions": "Istruzioni agente iniettate"
231
233
  },
232
234
  "delegation": {
233
- "taskDelegated": "Attivit\u00e0 delegata",
235
+ "taskDelegated": "Attività delegata",
234
236
  "to": "A:",
235
- "task": "Attivit\u00e0:",
236
- "why": "Perch\u00e9:",
237
+ "task": "Attività:",
238
+ "why": "Perché:",
237
239
  "alternatives": "Alternative:",
238
240
  "autoForwarding": "Inoltro automatico a {{name}}...",
239
241
  "via": "tramite"
240
242
  },
241
243
  "workPlan": {
242
244
  "phases": "{{count}} fasi",
243
- "tasks": "{{count}} attivit\u00e0",
245
+ "tasks": "{{count}} attività",
244
246
  "parallel": "parallelo",
245
247
  "sequential": "sequenziale",
246
248
  "dependsOn": "dipende da:",
@@ -251,13 +253,13 @@
251
253
  },
252
254
  "progress": {
253
255
  "workingOn": "sta lavorando su...",
254
- "taskFinished": "Attivit\u00e0 completata",
255
- "taskFailed": "Attivit\u00e0 fallita"
256
+ "taskFinished": "Attività completata",
257
+ "taskFailed": "Attività fallita"
256
258
  },
257
259
  "exec": {
258
- "runningTasks": "Attivit\u00e0 in esecuzione",
260
+ "runningTasks": "Attività in esecuzione",
259
261
  "running": "in esecuzione",
260
- "stopTask": "Ferma attivit\u00e0",
262
+ "stopTask": "Ferma attività",
261
263
  "dismiss": "Chiudi",
262
264
  "clearCompleted": "Cancella completate"
263
265
  },
@@ -272,4 +274,4 @@
272
274
  "noContent": "Nessun contenuto di risposta disponibile.",
273
275
  "rawMarkdown": "Markdown grezzo"
274
276
  }
275
- }
277
+ }
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "すべてのBash出力をインライン表示",
50
+ "hideOutputsInline": "インラインBash出力を非表示"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "メッセージ情報",
@@ -272,4 +274,4 @@
272
274
  "noContent": "レスポンス内容がありません。",
273
275
  "rawMarkdown": "生Markdown"
274
276
  }
275
- }
277
+ }
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "Mostrar todas as saídas do bash em linha",
50
+ "hideOutputsInline": "Ocultar as saídas do bash em linha"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Info da Mensagem",
@@ -45,7 +45,9 @@
45
45
  "listFiles": "ListFiles",
46
46
  "searchFiles": "SearchFiles",
47
47
  "executeCommand": "ExecuteCommand"
48
- }
48
+ },
49
+ "showOutputsInline": "Показывать все выводы bash в строке",
50
+ "hideOutputsInline": "Скрыть встроенные выводы bash"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "Информация о сообщении",
@@ -45,7 +45,9 @@
45
45
  "listFiles": "列出文件",
46
46
  "searchFiles": "搜索文件",
47
47
  "executeCommand": "执行命令"
48
- }
48
+ },
49
+ "showOutputsInline": "内联显示所有 Bash 输出",
50
+ "hideOutputsInline": "隐藏内联 Bash 输出"
49
51
  },
50
52
  "metadata": {
51
53
  "messageInfo": "消息信息",
@@ -3,6 +3,7 @@ import * as path from 'path';
3
3
  import { StringDecoder } from 'string_decoder';
4
4
  import { createLogger } from '../../utils/logger.js';
5
5
  import { isTmuxEnabled, checkTmuxAvailability, spawnInTmux, killTmuxSession, interruptTmuxSession, } from './tmux-helper.js';
6
+ import { startGrokSessionWatcher } from '../../grok/session-watcher.js';
6
7
  const log = createLogger('Runner');
7
8
  export class RunnerProcessLifecycle {
8
9
  backend;
@@ -25,6 +26,35 @@ export class RunnerProcessLifecycle {
25
26
  this.recoveryStore = deps.recoveryStore;
26
27
  this.onDisableAutoRestart = deps.onDisableAutoRestart;
27
28
  }
29
+ /**
30
+ * Grok headless does not stream tool events on stdout. Tail session files
31
+ * and inject tool_start/tool_result into the same pipeline as stdout events.
32
+ */
33
+ attachGrokSideChannel(activeProcess, agentId, workingDir, sessionId) {
34
+ if (this.backend.name !== 'grok')
35
+ return;
36
+ const watcher = startGrokSessionWatcher({
37
+ agentId,
38
+ workingDir,
39
+ sessionId,
40
+ startedAt: activeProcess.startTime,
41
+ onEvent: (event) => {
42
+ this.stdoutPipeline.emitStandardEvent(agentId, event);
43
+ },
44
+ onSessionId: (sid) => {
45
+ const proc = this.activeProcesses.get(agentId);
46
+ if (proc && !proc.sessionId) {
47
+ proc.sessionId = sid;
48
+ if (proc.lastRequest && !proc.lastRequest.sessionId) {
49
+ proc.lastRequest.sessionId = sid;
50
+ }
51
+ }
52
+ this.bus.emit({ type: 'runner.session_id', agentId, sessionId: sid });
53
+ this.callbacks.onSessionId(agentId, sid);
54
+ },
55
+ });
56
+ activeProcess.sideChannelStop = () => watcher.stop();
57
+ }
28
58
  async run(request) {
29
59
  const { agentId, prompt, workingDir, sessionId, model, effort, useChrome, permissionMode = 'bypass', systemPrompt, forceNewSession, forkSession, customAgent, } = request;
30
60
  await this.stop(agentId);
@@ -90,6 +120,7 @@ export class RunnerProcessLifecycle {
90
120
  tmuxExpectedCommand: path.basename(executable),
91
121
  };
92
122
  this.activeProcesses.set(agentId, activeProcess);
123
+ this.attachGrokSideChannel(activeProcess, agentId, workingDir, forceNewSession ? undefined : sessionId);
93
124
  // Use file-tailing stdout pipeline for tmux mode
94
125
  const tailer = this.stdoutPipeline.handleTmuxLog(agentId, tmuxResult.logFile);
95
126
  activeProcess.tmuxTailer = tailer;
@@ -136,10 +167,25 @@ export class RunnerProcessLifecycle {
136
167
  turnState: 'processing',
137
168
  };
138
169
  this.activeProcesses.set(agentId, activeProcess);
170
+ this.attachGrokSideChannel(activeProcess, agentId, workingDir, forceNewSession ? undefined : sessionId);
139
171
  const stdoutDone = this.stdoutPipeline.handleStdout(agentId, childProcess);
140
172
  this.handleStderr(agentId, childProcess);
141
173
  childProcess.on('close', async (code, signal) => {
142
174
  await stdoutDone;
175
+ // Keep tailing session files briefly so the last tool_result lines flush to disk
176
+ // after the CLI exits (common race on Grok headless).
177
+ const sideStop = activeProcess.sideChannelStop;
178
+ activeProcess.sideChannelStop = undefined;
179
+ if (sideStop) {
180
+ setTimeout(() => {
181
+ try {
182
+ sideStop();
183
+ }
184
+ catch {
185
+ // ignore
186
+ }
187
+ }, 2000);
188
+ }
143
189
  this.bus.emit({
144
190
  type: 'runner.process_closed',
145
191
  agentId,
@@ -221,6 +267,13 @@ export class RunnerProcessLifecycle {
221
267
  if (activeProcess.tmuxTailer) {
222
268
  activeProcess.tmuxTailer.stop();
223
269
  }
270
+ try {
271
+ activeProcess.sideChannelStop?.();
272
+ }
273
+ catch {
274
+ // ignore
275
+ }
276
+ activeProcess.sideChannelStop = undefined;
224
277
  this.activeProcesses.delete(agentId);
225
278
  this.activityCallbacks.delete(agentId);
226
279
  // tmux mode: kill the tmux session and clean up
@@ -16,11 +16,24 @@ export class RunnerStdoutPipeline {
16
16
  // loops (respond → notify → respond → notify → ...). Once the notification is sent,
17
17
  // suppress all further text/tool output until a new user message arrives.
18
18
  notificationSent = new Set();
19
+ // Streaming thinking blocks share a uuid across token deltas. The UI marks a
20
+ // row as thinking via a single leading `[thinking]` prefix — only the first
21
+ // chunk of each stream should get it, otherwise merges become
22
+ // `[thinking] a[thinking] b…`.
23
+ thinkingStreamPrefixed = new Set();
24
+ // High-frequency token streams (Grok headless) produce dozens of tiny deltas
25
+ // per second. Coalesce them into ~one flush every STREAM_COALESCE_MS so the
26
+ // client doesn't remeasure/redraw the virtual list on every token.
27
+ streamCoalesce = new Map();
19
28
  constructor(deps) {
20
29
  this.backend = deps.backend;
21
30
  this.callbacks = deps.callbacks;
22
31
  this.bus = deps.bus;
23
32
  }
33
+ /** Backends that emit token-sized streaming-json deltas. */
34
+ shouldCoalesceStreaming() {
35
+ return this.backend.name === 'grok';
36
+ }
24
37
  handleStdout(agentId, process) {
25
38
  return new Promise((resolve) => {
26
39
  const decoder = new StringDecoder('utf8');
@@ -134,25 +147,75 @@ export class RunnerStdoutPipeline {
134
147
  case 'init':
135
148
  this.lastEmittedText.delete(agentId);
136
149
  this.notificationSent.delete(agentId);
150
+ this.clearThinkingPrefixState(agentId);
137
151
  this.callbacks.onOutput(agentId, `Session started: ${event.sessionId} (${event.model})`);
138
152
  break;
139
153
  case 'text':
140
154
  if (event.text) {
141
155
  // Suppress consecutive identical text (extra safety for OpenCode agentic loop)
156
+ // Skip for streaming chunks — token-level deltas are intentionally small and
157
+ // may legitimately repeat, and they are merged client-side by uuid.
142
158
  const prevText = this.lastEmittedText.get(agentId);
143
- if (prevText && prevText === event.text.trim()) {
159
+ if (!event.isStreaming && prevText && prevText === event.text.trim()) {
144
160
  log.log(`[text] Suppressing duplicate text for agent ${agentId.slice(0, 4)}`);
145
161
  this.textEmittedInTurn.add(agentId);
146
162
  break;
147
163
  }
148
- this.lastEmittedText.set(agentId, event.text.trim());
149
- this.callbacks.onOutput(agentId, event.text, event.isStreaming, undefined, event.uuid);
164
+ if (event.isStreaming && event.uuid && this.shouldCoalesceStreaming()) {
165
+ this.enqueueStreamChunk(agentId, event.uuid, 'text', event.text);
166
+ }
167
+ else {
168
+ // Flush any pending coalesced deltas before a final/non-stream emit
169
+ // so the client never applies final full-text over a stale partial.
170
+ if (event.uuid) {
171
+ this.flushStreamCoalesce(`${agentId}:text:${event.uuid}`);
172
+ }
173
+ if (!event.isStreaming) {
174
+ this.lastEmittedText.set(agentId, event.text.trim());
175
+ }
176
+ this.callbacks.onOutput(agentId, event.text, event.isStreaming, undefined, event.uuid);
177
+ }
150
178
  this.textEmittedInTurn.add(agentId);
151
179
  }
152
180
  break;
153
181
  case 'thinking':
154
182
  if (event.text) {
155
- this.callbacks.onOutput(agentId, `[thinking] ${event.text}`, event.isStreaming, undefined, event.uuid);
183
+ const streamKey = event.uuid ? `${agentId}:${event.uuid}` : undefined;
184
+ if (!event.isStreaming) {
185
+ if (event.uuid) {
186
+ this.flushStreamCoalesce(`${agentId}:thinking:${event.uuid}`);
187
+ }
188
+ const thinkingOut = event.text.startsWith('[thinking]')
189
+ ? event.text
190
+ : `[thinking] ${event.text}`;
191
+ this.callbacks.onOutput(agentId, thinkingOut, false, undefined, event.uuid);
192
+ if (streamKey) {
193
+ this.thinkingStreamPrefixed.delete(streamKey);
194
+ }
195
+ break;
196
+ }
197
+ // Streaming path
198
+ if (event.uuid && this.shouldCoalesceStreaming()) {
199
+ let chunk = event.text;
200
+ if (streamKey && !this.thinkingStreamPrefixed.has(streamKey)) {
201
+ this.thinkingStreamPrefixed.add(streamKey);
202
+ chunk = `[thinking] ${event.text}`;
203
+ }
204
+ this.enqueueStreamChunk(agentId, event.uuid, 'thinking', chunk);
205
+ }
206
+ else {
207
+ let thinkingOut = event.text;
208
+ if (streamKey) {
209
+ if (!this.thinkingStreamPrefixed.has(streamKey)) {
210
+ this.thinkingStreamPrefixed.add(streamKey);
211
+ thinkingOut = `[thinking] ${event.text}`;
212
+ }
213
+ }
214
+ else if (!event.text.startsWith('[thinking]')) {
215
+ thinkingOut = `[thinking] ${event.text}`;
216
+ }
217
+ this.callbacks.onOutput(agentId, thinkingOut, true, undefined, event.uuid);
218
+ }
156
219
  }
157
220
  break;
158
221
  case 'tool_start': {
@@ -195,6 +258,8 @@ export class RunnerStdoutPipeline {
195
258
  break;
196
259
  }
197
260
  case 'step_complete': {
261
+ // Flush any pending coalesced stream chunks before finalizing the turn
262
+ this.flushAllStreamCoalesceForAgent(agentId);
198
263
  const hasErrorResultText = this.isLikelyErrorResultText(event.resultText);
199
264
  if (event.resultText && (!this.textEmittedInTurn.has(agentId) || hasErrorResultText)) {
200
265
  log.log(`[step_complete] Emitting resultText as fallback (no prior text events) for agent ${agentId.slice(0, 4)}`);
@@ -203,6 +268,8 @@ export class RunnerStdoutPipeline {
203
268
  else if (event.resultText) {
204
269
  log.log(`[step_complete] Skipping resultText (already emitted via text events) for agent ${agentId.slice(0, 4)}`);
205
270
  }
271
+ this.textEmittedInTurn.delete(agentId);
272
+ this.clearThinkingPrefixState(agentId);
206
273
  if (event.permissionDenials && event.permissionDenials.length > 0) {
207
274
  for (const denial of event.permissionDenials) {
208
275
  // Suppress the "[System] Permission denied" line for the two tools
@@ -245,6 +312,60 @@ export class RunnerStdoutPipeline {
245
312
  break;
246
313
  }
247
314
  }
315
+ clearThinkingPrefixState(agentId) {
316
+ const prefix = `${agentId}:`;
317
+ for (const key of this.thinkingStreamPrefixed) {
318
+ if (key.startsWith(prefix)) {
319
+ this.thinkingStreamPrefixed.delete(key);
320
+ }
321
+ }
322
+ // Drop any pending coalesced chunks for this agent
323
+ for (const [key, buf] of this.streamCoalesce) {
324
+ if (buf.agentId === agentId) {
325
+ if (buf.timer)
326
+ clearTimeout(buf.timer);
327
+ this.streamCoalesce.delete(key);
328
+ }
329
+ }
330
+ }
331
+ static STREAM_COALESCE_MS = 80;
332
+ enqueueStreamChunk(agentId, uuid, kind, chunk) {
333
+ const key = `${agentId}:${kind}:${uuid}`;
334
+ let buf = this.streamCoalesce.get(key);
335
+ if (!buf) {
336
+ buf = { agentId, uuid, kind, chunks: [], timer: null };
337
+ this.streamCoalesce.set(key, buf);
338
+ }
339
+ buf.chunks.push(chunk);
340
+ if (buf.timer)
341
+ return;
342
+ buf.timer = setTimeout(() => {
343
+ this.flushStreamCoalesce(key);
344
+ }, RunnerStdoutPipeline.STREAM_COALESCE_MS);
345
+ }
346
+ flushStreamCoalesce(key) {
347
+ const buf = this.streamCoalesce.get(key);
348
+ if (!buf)
349
+ return;
350
+ if (buf.timer) {
351
+ clearTimeout(buf.timer);
352
+ buf.timer = null;
353
+ }
354
+ if (buf.chunks.length === 0) {
355
+ this.streamCoalesce.delete(key);
356
+ return;
357
+ }
358
+ const text = buf.chunks.join('');
359
+ buf.chunks = [];
360
+ this.streamCoalesce.delete(key);
361
+ this.callbacks.onOutput(buf.agentId, text, true, undefined, buf.uuid);
362
+ }
363
+ flushAllStreamCoalesceForAgent(agentId) {
364
+ const keys = [...this.streamCoalesce.keys()].filter((k) => k.startsWith(`${agentId}:`));
365
+ for (const key of keys) {
366
+ this.flushStreamCoalesce(key);
367
+ }
368
+ }
248
369
  isNotificationCurl(toolInput) {
249
370
  const cmd = typeof toolInput?.command === 'string' ? toolInput.command : '';
250
371
  return cmd.includes('/api/notify');
@@ -71,6 +71,12 @@ export class RunnerWatchdog {
71
71
  log.error(`🐕 [WATCHDOG] Agent ${agentId}: tailer drain failed: ${String(err)}`);
72
72
  }
73
73
  activeProcess.tmuxTailer?.stop();
74
+ try {
75
+ activeProcess.sideChannelStop?.();
76
+ }
77
+ catch {
78
+ // ignore
79
+ }
74
80
  this.recordDeath({
75
81
  agentId,
76
82
  pid: activeProcess.process.pid ?? 0,
@@ -125,6 +131,12 @@ export class RunnerWatchdog {
125
131
  timestamp: Date.now(),
126
132
  stderr: this.lastStderr.get(agentId),
127
133
  });
134
+ try {
135
+ activeProcess.sideChannelStop?.();
136
+ }
137
+ catch {
138
+ // ignore
139
+ }
128
140
  this.activeProcesses.delete(agentId);
129
141
  this.lastStderr.delete(agentId);
130
142
  const remaining = this.activeProcesses.size;