tide-commander 1.152.0 → 1.154.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 (72) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/assets/{BossLogsModal-DZWUfQXs.js → BossLogsModal-Bo0pUCWU.js} +1 -1
  3. package/dist/assets/{BossSpawnModal-7IwzcqE7.js → BossSpawnModal-BOOHaqaD.js} +1 -1
  4. package/dist/assets/{ControlsModal-D8L1xD-H.js → ControlsModal-DItGV-CW.js} +1 -1
  5. package/dist/assets/{DockerLogsModal-_zLe5UFl.js → DockerLogsModal-DjAZ3GL7.js} +1 -1
  6. package/dist/assets/{EmbeddedEditor-gbiFXvt_.js → EmbeddedEditor-Cihkr8Xb.js} +1 -1
  7. package/dist/assets/{GmailOAuthSetup-CcXTV3NP.js → GmailOAuthSetup-G1XqiM44.js} +1 -1
  8. package/dist/assets/{GoogleOAuthSetup-wbETidgv.js → GoogleOAuthSetup-Ce6gojdm.js} +1 -1
  9. package/dist/assets/{IframeModal-a9E5UDBk.js → IframeModal-CSSZJzPv.js} +1 -1
  10. package/dist/assets/{IntegrationsPanel-BbGyluL0.js → IntegrationsPanel-EspPH09n.js} +2 -2
  11. package/dist/assets/LogViewerModal-Bn-HDysM.js +1 -0
  12. package/dist/assets/{MonitoringModal-DymqjenY.js → MonitoringModal-DuSLTKVR.js} +1 -1
  13. package/dist/assets/{PM2LogsModal-CEaCk-dt.js → PM2LogsModal-Bo2OtaQd.js} +1 -1
  14. package/dist/assets/{RestoreArchivedAreaModal-q_FFv7L6.js → RestoreArchivedAreaModal-BOx-V6tl.js} +1 -1
  15. package/dist/assets/{Scene2DCanvas-DOvVtiYO.js → Scene2DCanvas-BIUbi14G.js} +1 -1
  16. package/dist/assets/{SceneManager-D0NdrG8K.js → SceneManager-CIWrGc-K.js} +4 -4
  17. package/dist/assets/{SkillsPanel-DpqD60Hy.js → SkillsPanel-_KHtTDhC.js} +1 -1
  18. package/dist/assets/{SlackMultiInstanceSetup-BdoALd_g.js → SlackMultiInstanceSetup-DbQ3rUtd.js} +1 -1
  19. package/dist/assets/{SpawnModal-DFFFH2kc.js → SpawnModal-CYEoOMPW.js} +1 -1
  20. package/dist/assets/{StatisticsModal-Dv_rYZDt.js → StatisticsModal-BJ-coeis.js} +1 -1
  21. package/dist/assets/{SubordinateAssignmentModal-CRCCI686.js → SubordinateAssignmentModal-5Z3jvbM9.js} +1 -1
  22. package/dist/assets/SymbolsNerdFontMono-Regular-BM2yZ5nr.woff2 +0 -0
  23. package/dist/assets/{TriggerManagerPanel-DBN8IRa-.js → TriggerManagerPanel-DvC0xP9r.js} +1 -1
  24. package/dist/assets/{WorkflowEditorPanel-uQEvNTs2.js → WorkflowEditorPanel-6ym1_csr.js} +1 -1
  25. package/dist/assets/{area-logos-CuVxToGM.js → area-logos-mWPCtCnf.js} +1 -1
  26. package/dist/assets/{index-Dwll5Eyj.js → index-8VVbTmtb.js} +1 -1
  27. package/dist/assets/{index-BNzYPyBm.css → index-BPjQZacc.css} +1 -1
  28. package/dist/assets/index-C34l72MW.js +1 -0
  29. package/dist/assets/{index-DKnfLe7S.js → index-CS8OutmQ.js} +1 -1
  30. package/dist/assets/{index-ipuWrg1S.js → index-CT2vtbed.js} +3 -3
  31. package/dist/assets/{index-Blc4MwKs.js → index-CY_NzVPm.js} +1 -1
  32. package/dist/assets/index-CiKbhMfN.js +1 -0
  33. package/dist/assets/{index-HvyFhszc.js → index-CnESn83U.js} +2 -2
  34. package/dist/assets/{index-8Ghh3AQ-.js → index-DZiNmiyC.js} +1 -1
  35. package/dist/assets/{index-D4iie3Vd.js → index-DxyZ-rYT.js} +1 -1
  36. package/dist/assets/main-BHBs2E1L.css +1 -0
  37. package/dist/assets/main-D5j8Ul0m.js +289 -0
  38. package/dist/assets/{web-D0JSbYeo.js → web-BvAQVbIF.js} +1 -1
  39. package/dist/assets/{web-1pfPwxBS.js → web-Cd0-XOkz.js} +1 -1
  40. package/dist/assets/{web-DjgiLxvi.js → web-DMxl9AVF.js} +1 -1
  41. package/dist/build-info.json +1 -0
  42. package/dist/index.html +2 -2
  43. package/dist/locales/de/config.json +1 -0
  44. package/dist/locales/en/config.json +6 -1
  45. package/dist/locales/en/terminal.json +36 -0
  46. package/dist/locales/es/config.json +4 -1
  47. package/dist/locales/es/terminal.json +8 -0
  48. package/dist/locales/fr/config.json +1 -0
  49. package/dist/locales/hi/config.json +1 -0
  50. package/dist/locales/it/config.json +1 -0
  51. package/dist/locales/ja/config.json +1 -0
  52. package/dist/locales/pt/config.json +1 -0
  53. package/dist/locales/ru/config.json +1 -0
  54. package/dist/locales/zh-CN/config.json +1 -0
  55. package/dist/src/packages/server/codex/app-server/app-server-event-adapter.js +222 -0
  56. package/dist/src/packages/server/codex/app-server/app-server-process.js +304 -0
  57. package/dist/src/packages/server/codex/app-server/app-server-recovery-store.js +76 -0
  58. package/dist/src/packages/server/codex/app-server/codex-app-server-runner.js +453 -0
  59. package/dist/src/packages/server/routes/agents.js +29 -1
  60. package/dist/src/packages/server/routes/system.js +216 -1
  61. package/dist/src/packages/server/runtime/codex-runner-router.js +99 -0
  62. package/dist/src/packages/server/runtime/codex-runtime-provider.js +5 -3
  63. package/dist/src/packages/server/services/claude-credentials-service.js +536 -0
  64. package/dist/src/packages/server/services/claude-usage-service.js +35 -28
  65. package/dist/src/packages/server/services/provider-credentials-service.js +338 -0
  66. package/dist/src/packages/server/services/system-prompt-service.js +46 -0
  67. package/package.json +1 -1
  68. package/dist/assets/LogViewerModal-cnMAbNvY.js +0 -1
  69. package/dist/assets/index-BHM8V4i-.js +0 -1
  70. package/dist/assets/index-OkenGYC6.js +0 -1
  71. package/dist/assets/main-DpNJ8pqp.css +0 -1
  72. package/dist/assets/main-aIpEYDDR.js +0 -289
@@ -1 +1 @@
1
- import{de as a}from"./main-aIpEYDDR.js";import{ImpactStyle as i,NotificationType as r}from"./index-HvyFhszc.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{df as a}from"./main-D5j8Ul0m.js";import{ImpactStyle as i,NotificationType as r}from"./index-CnESn83U.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 +1 @@
1
- import{de as t}from"./main-aIpEYDDR.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{df as t}from"./main-D5j8Ul0m.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{de as s}from"./main-aIpEYDDR.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{df as s}from"./main-D5j8Ul0m.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};
@@ -0,0 +1 @@
1
+ {"version":"1.154.0"}
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-aIpEYDDR.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-D5j8Ul0m.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-DpNJ8pqp.css">
28
+ <link rel="stylesheet" crossorigin href="/assets/main-BHBs2E1L.css">
29
29
  </head>
30
30
  <body>
31
31
  <div id="app"></div>
@@ -25,6 +25,7 @@
25
25
  "showFPS": "FPS anzeigen",
26
26
  "fpsLimit": "FPS-Limit",
27
27
  "powerSaving": "Energiesparmodus",
28
+ "lowPowerMode": "Energiesparmodus (niedrig)",
28
29
  "tts": "Text-zu-Sprache",
29
30
  "stt": "Sprache-zu-Text",
30
31
  "externalEditor": "Externer Editor",
@@ -12,6 +12,7 @@
12
12
  "modelStyle": "Agent Model Style",
13
13
  "animations": "Animations",
14
14
  "secrets": "Secrets",
15
+ "claudeAccounts": "Claude Accounts",
15
16
  "systemPrompt": "System Prompt",
16
17
  "whatsapp": "WhatsApp Integration",
17
18
  "whatsappNotifications": "WhatsApp Notifications",
@@ -20,7 +21,9 @@
20
21
  "integrations": "Integrations",
21
22
  "experimental": "Experimental",
22
23
  "about": "About",
23
- "sky": "Sky Color"
24
+ "sky": "Sky Color",
25
+ "grokAccounts": "Grok Accounts",
26
+ "codexAccounts": "Codex Accounts"
24
27
  },
25
28
  "general": {
26
29
  "history": "History",
@@ -31,8 +34,10 @@
31
34
  "showFPS": "Show FPS",
32
35
  "fpsLimit": "FPS Limit",
33
36
  "powerSaving": "Power Saving",
37
+ "lowPowerMode": "Low Power Mode",
34
38
  "tmuxMode": "Tmux Process Persistence",
35
39
  "interactiveMode": "Interactive TUI Mode (Experimental)",
40
+ "codexAppServerMode": "Codex Streaming / app-server (Experimental)",
36
41
  "tts": "Text-to-Speech",
37
42
  "stt": "Speech-to-Text",
38
43
  "externalEditor": "External Editor",
@@ -1294,5 +1294,41 @@
1294
1294
  "percentUsed": "{{percent}}% used",
1295
1295
  "resets": "Resets {{time}}",
1296
1296
  "limitsError": "Live limits unavailable: {{message}}"
1297
+ },
1298
+ "credentials": {
1299
+ "title": "Claude accounts",
1300
+ "help": "Named copies of ~/.claude/.credentials.json (e.g. .credentials.david.json). Switch the active account when you hit rate limits — same as renaming the file manually.",
1301
+ "current": "Active: {{name}}",
1302
+ "unsavedActive": "current (not saved as a named profile)",
1303
+ "noActive": "none",
1304
+ "activeBadge": "Active",
1305
+ "invalid": "Invalid",
1306
+ "use": "Use",
1307
+ "useTitle": "Make this the active Claude account",
1308
+ "rename": "Rename profile",
1309
+ "delete": "Delete named profile",
1310
+ "saveActive": "Save active as…",
1311
+ "savePlaceholder": "Profile name (e.g. david)",
1312
+ "nameRequired": "Enter a profile name.",
1313
+ "saved": "Saved active account as \"{{name}}\".",
1314
+ "switched": "Switched active Claude account to \"{{name}}\".",
1315
+ "switchedWithStash": "Saved previous account as \"{{stash}}\", then switched to \"{{name}}\".",
1316
+ "stashRequired": "Name the current account before switching so it is not lost.",
1317
+ "stashPrompt": "Current active credentials are not saved as a named profile. Name them before switching to \"{{name}}\":",
1318
+ "stashPlaceholder": "Name for current account (e.g. previous)",
1319
+ "confirmSwitch": "Save & switch",
1320
+ "confirmOverwrite": "Profile \"{{name}}\" already exists with different credentials. Overwrite?",
1321
+ "confirmDelete": "Delete named profile \"{{name}}\"? The active file is not removed.",
1322
+ "renamePrompt": "Rename profile \"{{name}}\" to:",
1323
+ "renamed": "Renamed \"{{from}}\" → \"{{to}}\".",
1324
+ "deleted": "Deleted profile \"{{name}}\".",
1325
+ "noProfiles": "No named profiles yet. Save the active account with a name (e.g. david, jc) to create one.",
1326
+ "tokenExpires": "token expires {{time}}",
1327
+ "gaugeSession": "Session",
1328
+ "gaugeWeek": "Week",
1329
+ "gaugeWeekOpus": "Opus wk",
1330
+ "gaugeNoSession": "no active session",
1331
+ "providerTitle": "{{provider}} Accounts",
1332
+ "providerHelp": "Named copies of {{dir}}/auth.json. Switch the active {{provider}} account when you hit rate limits — same as renaming the file manually."
1297
1333
  }
1298
1334
  }
@@ -16,7 +16,9 @@
16
16
  "experimental": "Experimental",
17
17
  "about": "Acerca de",
18
18
  "sky": "Color del Cielo",
19
- "systemPrompt": "Prompt de sistema"
19
+ "systemPrompt": "Prompt de sistema",
20
+ "grokAccounts": "Cuentas de Grok",
21
+ "codexAccounts": "Cuentas de Codex"
20
22
  },
21
23
  "general": {
22
24
  "history": "Historial",
@@ -27,6 +29,7 @@
27
29
  "showFPS": "Mostrar FPS",
28
30
  "fpsLimit": "Limite de FPS",
29
31
  "powerSaving": "Ahorro de energia",
32
+ "lowPowerMode": "Modo bajo consumo",
30
33
  "tts": "Texto a voz",
31
34
  "stt": "Voz a texto",
32
35
  "externalEditor": "Editor externo",
@@ -1132,5 +1132,13 @@
1132
1132
  "can-clear-context": "Completado — contexto listo para limpiar",
1133
1133
  "waiting-subordinates": "Esperando trabajo delegado",
1134
1134
  "working": "Trabajando"
1135
+ },
1136
+ "credentials": {
1137
+ "gaugeSession": "Sesión",
1138
+ "gaugeWeek": "Semana",
1139
+ "gaugeWeekOpus": "Opus sem",
1140
+ "gaugeNoSession": "sin sesión activa",
1141
+ "providerTitle": "Cuentas de {{provider}}",
1142
+ "providerHelp": "Copias nombradas de {{dir}}/auth.json. Cambia la cuenta activa de {{provider}} cuando llegues a los límites — igual que renombrar el archivo a mano."
1135
1143
  }
1136
1144
  }
@@ -25,6 +25,7 @@
25
25
  "showFPS": "Afficher les FPS",
26
26
  "fpsLimit": "Limite de FPS",
27
27
  "powerSaving": "Économie d'énergie",
28
+ "lowPowerMode": "Mode basse consommation",
28
29
  "tts": "Synthèse vocale",
29
30
  "stt": "Reconnaissance vocale",
30
31
  "externalEditor": "Éditeur externe",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "FPS दिखाएं",
26
26
  "fpsLimit": "FPS सीमा",
27
27
  "powerSaving": "बिजली बचत",
28
+ "lowPowerMode": "लो पावर मोड",
28
29
  "tts": "टेक्स्ट-टू-स्पीच",
29
30
  "stt": "स्पीच-टू-टेक्स्ट",
30
31
  "externalEditor": "बाहरी संपादक",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "Mostra FPS",
26
26
  "fpsLimit": "Limite FPS",
27
27
  "powerSaving": "Risparmio energetico",
28
+ "lowPowerMode": "Modalità basso consumo",
28
29
  "tts": "Sintesi vocale",
29
30
  "stt": "Riconoscimento vocale",
30
31
  "externalEditor": "Editor esterno",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "FPSを表示",
26
26
  "fpsLimit": "FPS制限",
27
27
  "powerSaving": "省電力モード",
28
+ "lowPowerMode": "低電力モード",
28
29
  "tts": "テキスト読み上げ",
29
30
  "stt": "音声認識",
30
31
  "externalEditor": "外部エディタ",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "Mostrar FPS",
26
26
  "fpsLimit": "Limite de FPS",
27
27
  "powerSaving": "Economia de Energia",
28
+ "lowPowerMode": "Modo de baixo consumo",
28
29
  "tts": "Texto para Fala",
29
30
  "stt": "Fala para Texto",
30
31
  "externalEditor": "Editor Externo",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "Показать FPS",
26
26
  "fpsLimit": "Ограничение FPS",
27
27
  "powerSaving": "Энергосбережение",
28
+ "lowPowerMode": "Режим низкого энергопотребления",
28
29
  "tts": "Синтез речи",
29
30
  "stt": "Распознавание речи",
30
31
  "externalEditor": "Внешний редактор",
@@ -25,6 +25,7 @@
25
25
  "showFPS": "显示帧率",
26
26
  "fpsLimit": "帧率限制",
27
27
  "powerSaving": "省电模式",
28
+ "lowPowerMode": "低功耗模式",
28
29
  "tts": "文字转语音",
29
30
  "stt": "语音转文字",
30
31
  "externalEditor": "外部编辑器",
@@ -0,0 +1,222 @@
1
+ /**
2
+ * CodexAppServerEventAdapter
3
+ *
4
+ * Translates `codex app-server` JSON-RPC notifications (v2 protocol, camelCase
5
+ * items) into Tide `StandardEvent`s, one adapter instance per agent (it holds
6
+ * per-turn state: the last agent-message text for boss delegation, and the most
7
+ * recent token-usage snapshot).
8
+ *
9
+ * The uuid conventions match the exec parser
10
+ * (src/packages/server/codex/json-event-parser.ts): `codex-text-<itemId>` for
11
+ * assistant text and `codex-thinking-<itemId>` for reasoning, so streaming
12
+ * deltas merge into one terminal row and the final `isStreaming:false` event
13
+ * finalizes it — identical downstream behaviour to the exec path, just with
14
+ * real token-level streaming.
15
+ */
16
+ import { createLogger } from '../../utils/logger.js';
17
+ const log = createLogger('CodexAppServerAdapter');
18
+ function asString(v) {
19
+ return typeof v === 'string' ? v : undefined;
20
+ }
21
+ function asNumber(v) {
22
+ return typeof v === 'number' ? v : undefined;
23
+ }
24
+ export class CodexAppServerEventAdapter {
25
+ lastAgentMessageText;
26
+ lastErrorText;
27
+ tokenSnapshot;
28
+ /** Map one app-server notification to zero or more Tide events. */
29
+ handle(method, params) {
30
+ switch (method) {
31
+ // ---- Streaming deltas (the whole point) --------------------------------
32
+ case 'item/agentMessage/delta': {
33
+ const delta = asString(params.delta);
34
+ const itemId = asString(params.itemId) || 'anon';
35
+ if (!delta)
36
+ return [];
37
+ return [{ type: 'text', text: delta, isStreaming: true, uuid: `codex-text-${itemId}` }];
38
+ }
39
+ case 'item/reasoning/textDelta':
40
+ case 'item/reasoning/summaryTextDelta': {
41
+ const delta = asString(params.delta);
42
+ const itemId = asString(params.itemId) || 'anon';
43
+ if (!delta)
44
+ return [];
45
+ return [{ type: 'thinking', text: delta, isStreaming: true, uuid: `codex-thinking-${itemId}` }];
46
+ }
47
+ // ---- Item lifecycle ----------------------------------------------------
48
+ case 'item/started':
49
+ return this.handleItemStarted(params.item || {});
50
+ case 'item/completed':
51
+ return this.handleItemCompleted(params.item || {});
52
+ // ---- Turn + usage ------------------------------------------------------
53
+ case 'thread/tokenUsage/updated':
54
+ this.captureTokenUsage(params.tokenUsage);
55
+ return [];
56
+ case 'turn/completed':
57
+ return this.handleTurnCompleted(params.turn);
58
+ // ---- Errors ------------------------------------------------------------
59
+ case 'error': {
60
+ const errorMessage = asString(params.message) || 'Codex app-server error';
61
+ this.lastErrorText = errorMessage;
62
+ return [{ type: 'error', errorMessage }];
63
+ }
64
+ // Informational / handled elsewhere — stay silent (no raw dumps).
65
+ case 'thread/started':
66
+ case 'turn/started':
67
+ case 'thread/status/changed':
68
+ case 'thread/tokenUsage':
69
+ case 'item/plan/delta':
70
+ case 'turn/plan/updated':
71
+ case 'turn/diff/updated':
72
+ case 'item/reasoning/summaryPartAdded':
73
+ case 'item/commandExecution/outputDelta':
74
+ case 'account/rateLimits/updated':
75
+ case 'remoteControl/status/changed':
76
+ return [];
77
+ default:
78
+ // Unknown notification: swallow it (the exec parser dumps unknowns to the
79
+ // terminal, but at the notification layer that would be far too noisy).
80
+ log.debug(`Unhandled app-server notification: ${method}`);
81
+ return [];
82
+ }
83
+ }
84
+ handleItemStarted(item) {
85
+ switch (item.type) {
86
+ case 'commandExecution': {
87
+ const command = item.command || '';
88
+ return [{ type: 'tool_start', toolName: 'Bash', toolInput: { command, status: item.status } }];
89
+ }
90
+ case 'webSearch':
91
+ return [{ type: 'tool_start', toolName: 'web_search', toolInput: this.webSearchInput(item) }];
92
+ // agentMessage / reasoning: deltas carry the content; fileChange diff lands
93
+ // on completion. Everything else stays silent on start.
94
+ default:
95
+ return [];
96
+ }
97
+ }
98
+ handleItemCompleted(item) {
99
+ switch (item.type) {
100
+ case 'agentMessage': {
101
+ const text = (item.text || '').trim();
102
+ if (!text)
103
+ return [];
104
+ this.lastAgentMessageText = text;
105
+ return [{ type: 'text', text, isStreaming: false, uuid: item.id ? `codex-text-${item.id}` : undefined }];
106
+ }
107
+ case 'reasoning': {
108
+ const text = (item.content && item.content.length ? item.content : item.summary || []).join('\n').trim();
109
+ if (!text)
110
+ return [];
111
+ return [{ type: 'thinking', text, isStreaming: false, uuid: item.id ? `codex-thinking-${item.id}` : undefined }];
112
+ }
113
+ case 'commandExecution': {
114
+ const output = item.aggregatedOutput ??
115
+ (item.exitCode !== undefined ? `[exit ${item.exitCode}]` : item.status ? `Command status: ${item.status}` : '');
116
+ return [{ type: 'tool_result', toolName: 'Bash', toolOutput: output }];
117
+ }
118
+ case 'fileChange':
119
+ return this.handleFileChange(item);
120
+ case 'webSearch':
121
+ return [{ type: 'tool_result', toolName: 'web_search', toolOutput: JSON.stringify(this.webSearchInput(item)) }];
122
+ case 'collabAgentToolCall': {
123
+ const toolName = item.tool || 'collab_tool';
124
+ const toolInput = { tool: item.tool, status: item.status };
125
+ if (item.prompt)
126
+ toolInput.prompt = item.prompt;
127
+ if (item.receiverThreadIds?.length)
128
+ toolInput.receiver_thread_ids = item.receiverThreadIds;
129
+ return [
130
+ { type: 'tool_start', toolName, toolInput },
131
+ { type: 'tool_result', toolName, toolOutput: `Status: ${item.status || 'unknown'}` },
132
+ ];
133
+ }
134
+ case 'error': {
135
+ const errorMessage = item.message || item.text || item.error || 'Codex emitted an error';
136
+ this.lastErrorText = errorMessage;
137
+ return [{ type: 'error', errorMessage }];
138
+ }
139
+ default:
140
+ return [];
141
+ }
142
+ }
143
+ handleFileChange(item) {
144
+ if (!item.changes || item.changes.length === 0)
145
+ return [];
146
+ if (item.status && item.status !== 'completed')
147
+ return [];
148
+ const events = [];
149
+ for (const change of item.changes) {
150
+ if (!change.path)
151
+ continue;
152
+ const toolInput = { file_path: change.path };
153
+ // v2 fileChange carries a per-file unified diff inline — no git shell-out
154
+ // needed (the exec path has to reconstruct it via `git diff`).
155
+ if (change.diff)
156
+ toolInput.unified_diff = change.diff;
157
+ const kind = change.kind?.type || 'update';
158
+ events.push({ type: 'tool_start', toolName: 'Edit', toolInput }, { type: 'tool_result', toolName: 'Edit', toolOutput: `File ${kind}: ${change.path}` });
159
+ }
160
+ return events;
161
+ }
162
+ webSearchInput(item) {
163
+ return {
164
+ query: item.query,
165
+ actionType: item.action?.type,
166
+ actionQuery: item.action?.query,
167
+ actionQueries: item.action?.queries,
168
+ actionUrl: item.action?.url,
169
+ };
170
+ }
171
+ captureTokenUsage(tokenUsage) {
172
+ if (typeof tokenUsage !== 'object' || tokenUsage === null)
173
+ return;
174
+ const tu = tokenUsage;
175
+ const last = tu.last || {};
176
+ this.tokenSnapshot = {
177
+ contextWindow: asNumber(tu.modelContextWindow) ?? this.tokenSnapshot?.contextWindow,
178
+ inputTokens: asNumber(last.inputTokens),
179
+ outputTokens: asNumber(last.outputTokens),
180
+ cacheReadInputTokens: asNumber(last.cachedInputTokens),
181
+ };
182
+ }
183
+ handleTurnCompleted(turn) {
184
+ const events = [];
185
+ // A failed turn carries its error inline — surface it before finalizing.
186
+ if (turn && asString(turn.status) === 'failed') {
187
+ const err = turn.error;
188
+ const errorMessage = (err && asString(err.message)) || 'Codex turn failed';
189
+ this.lastErrorText = errorMessage;
190
+ events.push({ type: 'error', errorMessage });
191
+ }
192
+ const snap = this.tokenSnapshot;
193
+ const event = {
194
+ type: 'step_complete',
195
+ tokens: {
196
+ input: snap?.inputTokens ?? 0,
197
+ output: snap?.outputTokens ?? 0,
198
+ cacheRead: snap?.cacheReadInputTokens,
199
+ },
200
+ };
201
+ if (this.lastAgentMessageText || this.lastErrorText) {
202
+ const parts = [];
203
+ if (this.lastAgentMessageText)
204
+ parts.push(this.lastAgentMessageText);
205
+ if (this.lastErrorText)
206
+ parts.push(`[Error] ${this.lastErrorText}`);
207
+ event.resultText = parts.join('\n\n');
208
+ }
209
+ if (snap && (snap.contextWindow || snap.inputTokens !== undefined || snap.outputTokens !== undefined)) {
210
+ event.modelUsage = {
211
+ contextWindow: snap.contextWindow,
212
+ inputTokens: snap.inputTokens ?? 0,
213
+ outputTokens: snap.outputTokens ?? 0,
214
+ cacheReadInputTokens: snap.cacheReadInputTokens ?? 0,
215
+ };
216
+ }
217
+ this.lastAgentMessageText = undefined;
218
+ this.lastErrorText = undefined;
219
+ events.push(event);
220
+ return events;
221
+ }
222
+ }