@bitseek/hermes-webui 0.1.0-beta.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 (233) hide show
  1. package/README.md +213 -0
  2. package/bin/hermes-webui.mjs +588 -0
  3. package/package.json +25 -0
  4. package/scripts/sync-vendor.mjs +74 -0
  5. package/templates/launchd/com.bitseek.hermes-webui.plist +21 -0
  6. package/templates/systemd/hermes-webui.service +13 -0
  7. package/templates/windows/hermes-webui-task.ps1 +3 -0
  8. package/vendor/agent-frontend-shell/.bitseek-source.json +6 -0
  9. package/vendor/agent-frontend-shell/.dockerignore +7 -0
  10. package/vendor/agent-frontend-shell/.env.docker.example +89 -0
  11. package/vendor/agent-frontend-shell/.env.example +34 -0
  12. package/vendor/agent-frontend-shell/.github/FUNDING.yml +3 -0
  13. package/vendor/agent-frontend-shell/.github/workflows/browser-smoke.yml +42 -0
  14. package/vendor/agent-frontend-shell/.github/workflows/docker-smoke.yml +233 -0
  15. package/vendor/agent-frontend-shell/.github/workflows/native-windows-startup.yml +132 -0
  16. package/vendor/agent-frontend-shell/.github/workflows/release.yml +57 -0
  17. package/vendor/agent-frontend-shell/.github/workflows/tests.yml +88 -0
  18. package/vendor/agent-frontend-shell/.vscode/launch.json +59 -0
  19. package/vendor/agent-frontend-shell/.vscode/settings.json +13 -0
  20. package/vendor/agent-frontend-shell/AGENTS.md +80 -0
  21. package/vendor/agent-frontend-shell/ARCHITECTURE.md +1658 -0
  22. package/vendor/agent-frontend-shell/BUGS.md +52 -0
  23. package/vendor/agent-frontend-shell/CHANGELOG.md +7295 -0
  24. package/vendor/agent-frontend-shell/CONTRIBUTING.md +205 -0
  25. package/vendor/agent-frontend-shell/CONTRIBUTORS.md +107 -0
  26. package/vendor/agent-frontend-shell/DESIGN.md +173 -0
  27. package/vendor/agent-frontend-shell/Dockerfile +91 -0
  28. package/vendor/agent-frontend-shell/LICENSE +21 -0
  29. package/vendor/agent-frontend-shell/README-CUSTOM.md +76 -0
  30. package/vendor/agent-frontend-shell/README.md +705 -0
  31. package/vendor/agent-frontend-shell/ROADMAP.md +351 -0
  32. package/vendor/agent-frontend-shell/SPRINTS.md +147 -0
  33. package/vendor/agent-frontend-shell/TESTING.md +1932 -0
  34. package/vendor/agent-frontend-shell/THEMES.md +170 -0
  35. package/vendor/agent-frontend-shell/api/__init__.py +1 -0
  36. package/vendor/agent-frontend-shell/api/agent_health.py +392 -0
  37. package/vendor/agent-frontend-shell/api/agent_sessions.py +782 -0
  38. package/vendor/agent-frontend-shell/api/auth.py +592 -0
  39. package/vendor/agent-frontend-shell/api/background.py +87 -0
  40. package/vendor/agent-frontend-shell/api/clarify.py +238 -0
  41. package/vendor/agent-frontend-shell/api/commands.py +124 -0
  42. package/vendor/agent-frontend-shell/api/compression_anchor.py +134 -0
  43. package/vendor/agent-frontend-shell/api/config.py +5178 -0
  44. package/vendor/agent-frontend-shell/api/dashboard_probe.py +255 -0
  45. package/vendor/agent-frontend-shell/api/extensions.py +253 -0
  46. package/vendor/agent-frontend-shell/api/gateway_chat.py +435 -0
  47. package/vendor/agent-frontend-shell/api/gateway_watcher.py +230 -0
  48. package/vendor/agent-frontend-shell/api/goals.py +608 -0
  49. package/vendor/agent-frontend-shell/api/helpers.py +474 -0
  50. package/vendor/agent-frontend-shell/api/kanban_bridge.py +1255 -0
  51. package/vendor/agent-frontend-shell/api/metering.py +194 -0
  52. package/vendor/agent-frontend-shell/api/models.py +4210 -0
  53. package/vendor/agent-frontend-shell/api/oauth.py +770 -0
  54. package/vendor/agent-frontend-shell/api/onboarding.py +1046 -0
  55. package/vendor/agent-frontend-shell/api/passkeys.py +365 -0
  56. package/vendor/agent-frontend-shell/api/profiles.py +1499 -0
  57. package/vendor/agent-frontend-shell/api/providers.py +2175 -0
  58. package/vendor/agent-frontend-shell/api/request_diagnostics.py +160 -0
  59. package/vendor/agent-frontend-shell/api/rollback.py +320 -0
  60. package/vendor/agent-frontend-shell/api/routes.py +13990 -0
  61. package/vendor/agent-frontend-shell/api/run_journal.py +284 -0
  62. package/vendor/agent-frontend-shell/api/runner_client.py +156 -0
  63. package/vendor/agent-frontend-shell/api/runtime_adapter.py +431 -0
  64. package/vendor/agent-frontend-shell/api/session_discoverability.py +640 -0
  65. package/vendor/agent-frontend-shell/api/session_events.py +45 -0
  66. package/vendor/agent-frontend-shell/api/session_lifecycle.py +208 -0
  67. package/vendor/agent-frontend-shell/api/session_ops.py +207 -0
  68. package/vendor/agent-frontend-shell/api/session_recovery.py +655 -0
  69. package/vendor/agent-frontend-shell/api/skill_usage.py +32 -0
  70. package/vendor/agent-frontend-shell/api/startup.py +128 -0
  71. package/vendor/agent-frontend-shell/api/state_sync.py +187 -0
  72. package/vendor/agent-frontend-shell/api/streaming.py +7048 -0
  73. package/vendor/agent-frontend-shell/api/system_health.py +167 -0
  74. package/vendor/agent-frontend-shell/api/terminal.py +410 -0
  75. package/vendor/agent-frontend-shell/api/turn_journal.py +214 -0
  76. package/vendor/agent-frontend-shell/api/updates.py +1261 -0
  77. package/vendor/agent-frontend-shell/api/upload.py +322 -0
  78. package/vendor/agent-frontend-shell/api/usage.py +26 -0
  79. package/vendor/agent-frontend-shell/api/workspace.py +867 -0
  80. package/vendor/agent-frontend-shell/api/workspace_git.py +1261 -0
  81. package/vendor/agent-frontend-shell/api/worktrees.py +357 -0
  82. package/vendor/agent-frontend-shell/bootstrap.py +492 -0
  83. package/vendor/agent-frontend-shell/ctl.sh +427 -0
  84. package/vendor/agent-frontend-shell/docker-compose.custom.yml +26 -0
  85. package/vendor/agent-frontend-shell/docker-compose.three-container.yml +168 -0
  86. package/vendor/agent-frontend-shell/docker-compose.two-container.yml +147 -0
  87. package/vendor/agent-frontend-shell/docker-compose.yml +57 -0
  88. package/vendor/agent-frontend-shell/docker_init.bash +459 -0
  89. package/vendor/agent-frontend-shell/docs/CONTRACTS.md +207 -0
  90. package/vendor/agent-frontend-shell/docs/EXTENSIONS.md +212 -0
  91. package/vendor/agent-frontend-shell/docs/ISSUES.md +23 -0
  92. package/vendor/agent-frontend-shell/docs/UIUX-GUIDE.md +196 -0
  93. package/vendor/agent-frontend-shell/docs/advanced-chat-setup.md +83 -0
  94. package/vendor/agent-frontend-shell/docs/docker.md +337 -0
  95. package/vendor/agent-frontend-shell/docs/onboarding-agent-checklist.md +207 -0
  96. package/vendor/agent-frontend-shell/docs/onboarding.md +202 -0
  97. package/vendor/agent-frontend-shell/docs/remote-access.md +75 -0
  98. package/vendor/agent-frontend-shell/docs/rfcs/README.md +53 -0
  99. package/vendor/agent-frontend-shell/docs/rfcs/agent-source-boundary.md +70 -0
  100. package/vendor/agent-frontend-shell/docs/rfcs/canonical-session-resolution.md +124 -0
  101. package/vendor/agent-frontend-shell/docs/rfcs/hermes-run-adapter-contract.md +1079 -0
  102. package/vendor/agent-frontend-shell/docs/rfcs/turn-journal.md +195 -0
  103. package/vendor/agent-frontend-shell/docs/rfcs/webui-run-state-consistency-contract.md +157 -0
  104. package/vendor/agent-frontend-shell/docs/supervisor.md +280 -0
  105. package/vendor/agent-frontend-shell/docs/troubleshooting.md +132 -0
  106. package/vendor/agent-frontend-shell/docs/ui-ux/index.html +863 -0
  107. package/vendor/agent-frontend-shell/docs/ui-ux/two-stage-proposal.html +768 -0
  108. package/vendor/agent-frontend-shell/docs/why-hermes.md +489 -0
  109. package/vendor/agent-frontend-shell/docs/workspace-git.md +92 -0
  110. package/vendor/agent-frontend-shell/docs/wsl-autostart.md +126 -0
  111. package/vendor/agent-frontend-shell/eslint.runtime-guard.config.mjs +35 -0
  112. package/vendor/agent-frontend-shell/extensions/bitseek-design-system.md +330 -0
  113. package/vendor/agent-frontend-shell/extensions/branding/assets/apple-touch-icon.png +0 -0
  114. package/vendor/agent-frontend-shell/extensions/branding/assets/empty-logo.svg +739 -0
  115. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-192.png +0 -0
  116. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-32.png +0 -0
  117. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-512.png +0 -0
  118. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-512.svg +745 -0
  119. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon.ico +0 -0
  120. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon.svg +745 -0
  121. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon-v2.svg +751 -0
  122. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon-v3.svg +739 -0
  123. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon.svg +745 -0
  124. package/vendor/agent-frontend-shell/extensions/branding/branding.js +112 -0
  125. package/vendor/agent-frontend-shell/extensions/branding/config.json +14 -0
  126. package/vendor/agent-frontend-shell/extensions/branding/manifest.json +53 -0
  127. package/vendor/agent-frontend-shell/extensions/index.js +67 -0
  128. package/vendor/agent-frontend-shell/extensions/loader/hermes-loader.js +77 -0
  129. package/vendor/agent-frontend-shell/extensions/manifest.json +16 -0
  130. package/vendor/agent-frontend-shell/extensions/pages/ai-teammates/page.css +333 -0
  131. package/vendor/agent-frontend-shell/extensions/pages/ai-teammates/page.js +487 -0
  132. package/vendor/agent-frontend-shell/extensions/pages/manifest.json +6 -0
  133. package/vendor/agent-frontend-shell/extensions/pages/registry.css +56 -0
  134. package/vendor/agent-frontend-shell/extensions/pages/registry.js +302 -0
  135. package/vendor/agent-frontend-shell/extensions/themes/bitseek/index.css +93 -0
  136. package/vendor/agent-frontend-shell/extensions/themes/bitseek/index.js +98 -0
  137. package/vendor/agent-frontend-shell/install.sh +63 -0
  138. package/vendor/agent-frontend-shell/mcp_server.py +567 -0
  139. package/vendor/agent-frontend-shell/package.json +12 -0
  140. package/vendor/agent-frontend-shell/pyproject.toml +56 -0
  141. package/vendor/agent-frontend-shell/pytest.ini +3 -0
  142. package/vendor/agent-frontend-shell/requirements.txt +5 -0
  143. package/vendor/agent-frontend-shell/server.py +624 -0
  144. package/vendor/agent-frontend-shell/start.ps1 +210 -0
  145. package/vendor/agent-frontend-shell/start.sh +65 -0
  146. package/vendor/agent-frontend-shell/static/apple-touch-icon.png +0 -0
  147. package/vendor/agent-frontend-shell/static/boot.js +1990 -0
  148. package/vendor/agent-frontend-shell/static/commands.js +1402 -0
  149. package/vendor/agent-frontend-shell/static/favicon-192.png +0 -0
  150. package/vendor/agent-frontend-shell/static/favicon-32.png +0 -0
  151. package/vendor/agent-frontend-shell/static/favicon-512.png +0 -0
  152. package/vendor/agent-frontend-shell/static/favicon-512.svg +18 -0
  153. package/vendor/agent-frontend-shell/static/favicon.ico +0 -0
  154. package/vendor/agent-frontend-shell/static/favicon.svg +20 -0
  155. package/vendor/agent-frontend-shell/static/i18n.js +15389 -0
  156. package/vendor/agent-frontend-shell/static/icons.js +92 -0
  157. package/vendor/agent-frontend-shell/static/index.html +1506 -0
  158. package/vendor/agent-frontend-shell/static/login.js +177 -0
  159. package/vendor/agent-frontend-shell/static/manifest.json +53 -0
  160. package/vendor/agent-frontend-shell/static/messages.js +3521 -0
  161. package/vendor/agent-frontend-shell/static/onboarding.js +800 -0
  162. package/vendor/agent-frontend-shell/static/panels.js +7995 -0
  163. package/vendor/agent-frontend-shell/static/pwa-startup.js +83 -0
  164. package/vendor/agent-frontend-shell/static/sessions.js +5165 -0
  165. package/vendor/agent-frontend-shell/static/style.css +4774 -0
  166. package/vendor/agent-frontend-shell/static/sw.js +173 -0
  167. package/vendor/agent-frontend-shell/static/terminal.js +632 -0
  168. package/vendor/agent-frontend-shell/static/ui.js +8997 -0
  169. package/vendor/agent-frontend-shell/static/vendor/js-yaml/4.1.0/js-yaml.min.js +2 -0
  170. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.ttf +0 -0
  171. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.woff +0 -0
  172. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  173. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  174. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  175. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  176. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  177. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  178. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  179. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  180. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  181. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  182. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  183. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  184. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  185. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.ttf +0 -0
  186. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.woff +0 -0
  187. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.woff2 +0 -0
  188. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  189. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  190. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  191. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.ttf +0 -0
  192. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.woff +0 -0
  193. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.woff2 +0 -0
  194. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.ttf +0 -0
  195. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.woff +0 -0
  196. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.woff2 +0 -0
  197. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  198. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  199. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  200. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.ttf +0 -0
  201. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.woff +0 -0
  202. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.woff2 +0 -0
  203. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  204. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  205. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  206. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  207. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  208. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  209. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  210. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  211. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  212. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.ttf +0 -0
  213. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.woff +0 -0
  214. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.woff2 +0 -0
  215. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.ttf +0 -0
  216. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.woff +0 -0
  217. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  218. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.ttf +0 -0
  219. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.woff +0 -0
  220. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  221. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.ttf +0 -0
  222. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.woff +0 -0
  223. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  224. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.ttf +0 -0
  225. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.woff +0 -0
  226. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  227. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  228. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  229. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  230. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/katex.min.css +1 -0
  231. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/katex.min.js +1 -0
  232. package/vendor/agent-frontend-shell/static/vendor/smd.min.js +29 -0
  233. package/vendor/agent-frontend-shell/static/workspace.js +680 -0
@@ -0,0 +1,632 @@
1
+ const TERMINAL_UI={
2
+ open:false,
3
+ collapsed:false,
4
+ sessionId:null,
5
+ workspace:null,
6
+ source:null,
7
+ term:null,
8
+ fitAddon:null,
9
+ resizeObserver:null,
10
+ resizeTimer:null,
11
+ closeTimer:null,
12
+ typedLine:'',
13
+ height:null,
14
+ resizeHandleReady:false,
15
+ resizing:false,
16
+ resizeStartY:0,
17
+ resizeStartHeight:0,
18
+ };
19
+
20
+ const TERMINAL_HEIGHT_DEFAULT=260;
21
+ const TERMINAL_HEIGHT_MIN=180;
22
+ const TERMINAL_HEIGHT_MAX=520;
23
+ const TERMINAL_MOBILE_HEIGHT_DEFAULT=190;
24
+ const TERMINAL_MOBILE_HEIGHT_MIN=140;
25
+ const TERMINAL_MOBILE_HEIGHT_MAX=300;
26
+
27
+ function _terminalEls(){
28
+ return {
29
+ panel:$('composerTerminalPanel'),
30
+ inner:$('composerTerminalPanel')&&$('composerTerminalPanel').querySelector('.composer-terminal-inner'),
31
+ dock:$('composerTerminalDock'),
32
+ viewport:$('terminalViewport'),
33
+ surface:$('terminalSurface'),
34
+ toggle:$('btnTerminalToggle'),
35
+ workspace:$('terminalWorkspaceLabel'),
36
+ dockWorkspace:$('terminalDockWorkspaceLabel'),
37
+ handle:$('terminalResizeHandle'),
38
+ };
39
+ }
40
+
41
+ function _terminalSessionId(){
42
+ return S.session&&S.session.session_id;
43
+ }
44
+
45
+ function _terminalWorkspaceName(){
46
+ const ws=S.session&&S.session.workspace;
47
+ if(!ws)return '';
48
+ const parts=String(ws).split(/[\\/]+/).filter(Boolean);
49
+ return parts[parts.length-1]||ws;
50
+ }
51
+
52
+ function _isTerminalCloseCommand(value){
53
+ return ['exit','quit','logout','close'].includes(String(value||'').trim().toLowerCase());
54
+ }
55
+
56
+ function _trackTerminalInput(data){
57
+ if(data==='\r'||data==='\n'){
58
+ const command=TERMINAL_UI.typedLine;
59
+ TERMINAL_UI.typedLine='';
60
+ return command;
61
+ }
62
+ if(data==='\u0003'){
63
+ TERMINAL_UI.typedLine='';
64
+ return null;
65
+ }
66
+ if(data==='\u007f'||data==='\b'){
67
+ TERMINAL_UI.typedLine=TERMINAL_UI.typedLine.slice(0,-1);
68
+ return null;
69
+ }
70
+ if(data.length===1&&data>=' '){
71
+ TERMINAL_UI.typedLine+=data;
72
+ }else if(data.length>1&&/^[\x20-\x7e]+$/.test(data)){
73
+ TERMINAL_UI.typedLine+=data;
74
+ }
75
+ return null;
76
+ }
77
+
78
+ function _terminalCssVar(name,fallback){
79
+ const value=getComputedStyle(document.documentElement).getPropertyValue(name).trim();
80
+ return value||fallback;
81
+ }
82
+
83
+ function _terminalTheme(){
84
+ const isDark=document.documentElement.classList.contains('dark');
85
+ const background=_terminalCssVar('--code-bg',isDark?'#1A1A2E':'#F5F0E5');
86
+ const foreground=_terminalCssVar('--pre-text',_terminalCssVar('--text',isDark?'#E2E8F0':'#1A1610'));
87
+ const muted=_terminalCssVar('--muted',isDark?'#C0C0C0':'#5C5344');
88
+ const accent=_terminalCssVar('--accent-text',_terminalCssVar('--accent',isDark?'#FFD700':'#8B6508'));
89
+ const error=_terminalCssVar('--error',isDark?'#EF5350':'#C62828');
90
+ const success=_terminalCssVar('--success',isDark?'#4CAF50':'#3D8B40');
91
+ const warning=_terminalCssVar('--warning',isDark?'#FFA726':'#E68A00');
92
+ const info=_terminalCssVar('--info',isDark?'#4DD0E1':'#0288A8');
93
+ return {
94
+ background,
95
+ foreground,
96
+ cursor:accent,
97
+ selectionBackground:_terminalCssVar('--accent-bg-strong',isDark?'rgba(255,215,0,.18)':'rgba(184,134,11,.18)'),
98
+ black:isDark?'#0D0D1A':'#1A1610',
99
+ red:error,
100
+ green:success,
101
+ yellow:warning,
102
+ blue:info,
103
+ magenta:accent,
104
+ cyan:info,
105
+ white:foreground,
106
+ brightBlack:muted,
107
+ brightRed:error,
108
+ brightGreen:success,
109
+ brightYellow:accent,
110
+ brightBlue:info,
111
+ brightMagenta:accent,
112
+ brightCyan:info,
113
+ brightWhite:isDark?'#FFFFFF':'#0F0D08',
114
+ };
115
+ }
116
+
117
+ function syncComposerTerminalTheme(){
118
+ if(TERMINAL_UI.term)TERMINAL_UI.term.options.theme=_terminalTheme();
119
+ }
120
+
121
+ function _xtermReady(){
122
+ return typeof window.Terminal==='function';
123
+ }
124
+
125
+ function _ensureXterm(){
126
+ const {surface}= _terminalEls();
127
+ if(!surface)return null;
128
+ if(TERMINAL_UI.term)return TERMINAL_UI.term;
129
+ if(!_xtermReady()){
130
+ surface.textContent='Terminal library failed to load. Check network access to cdn.jsdelivr.net.';
131
+ return null;
132
+ }
133
+ const term=new window.Terminal({
134
+ cursorBlink:true,
135
+ fontSize:13,
136
+ fontFamily:'Menlo, Monaco, Consolas, "Liberation Mono", monospace',
137
+ scrollback:1000,
138
+ convertEol:false,
139
+ theme:_terminalTheme(),
140
+ });
141
+ let fitAddon=null;
142
+ if(window.FitAddon&&typeof window.FitAddon.FitAddon==='function'){
143
+ fitAddon=new window.FitAddon.FitAddon();
144
+ term.loadAddon(fitAddon);
145
+ }
146
+ if(window.WebLinksAddon&&typeof window.WebLinksAddon.WebLinksAddon==='function'){
147
+ term.loadAddon(new window.WebLinksAddon.WebLinksAddon());
148
+ }
149
+ term.open(surface);
150
+ term.onData(data=>{
151
+ const completedCommand=_trackTerminalInput(data);
152
+ if(completedCommand!==null&&_isTerminalCloseCommand(completedCommand)){
153
+ closeComposerTerminal();
154
+ return;
155
+ }
156
+ const sid=TERMINAL_UI.sessionId||_terminalSessionId();
157
+ if(!sid)return;
158
+ api('/api/terminal/input',{method:'POST',body:JSON.stringify({
159
+ session_id:sid,
160
+ data,
161
+ })}).catch(e=>showToast(t('terminal_input_failed')+e.message,2600,'error'));
162
+ });
163
+ TERMINAL_UI.term=term;
164
+ TERMINAL_UI.fitAddon=fitAddon;
165
+ _fitTerminal();
166
+ return term;
167
+ }
168
+
169
+ function _terminalDimensions(){
170
+ const term=TERMINAL_UI.term;
171
+ if(term&&term.cols&&term.rows)return {rows:term.rows,cols:term.cols};
172
+ return {rows:18,cols:80};
173
+ }
174
+
175
+ function _terminalHeightBounds(){
176
+ const mobile=window.matchMedia&&window.matchMedia('(max-width: 700px)').matches;
177
+ const min=mobile?TERMINAL_MOBILE_HEIGHT_MIN:TERMINAL_HEIGHT_MIN;
178
+ const maxByViewport=Math.floor(window.innerHeight*(mobile?0.44:0.5));
179
+ const hardMax=mobile?TERMINAL_MOBILE_HEIGHT_MAX:TERMINAL_HEIGHT_MAX;
180
+ return {
181
+ min,
182
+ max:Math.max(min,Math.min(hardMax,maxByViewport)),
183
+ defaultHeight:mobile?TERMINAL_MOBILE_HEIGHT_DEFAULT:TERMINAL_HEIGHT_DEFAULT,
184
+ };
185
+ }
186
+
187
+ function _clampTerminalHeight(height){
188
+ const bounds=_terminalHeightBounds();
189
+ const n=Number(height);
190
+ const fallback=TERMINAL_UI.height||bounds.defaultHeight;
191
+ return Math.max(bounds.min,Math.min(bounds.max,Number.isFinite(n)?n:fallback));
192
+ }
193
+
194
+ function _applyTerminalHeight(height){
195
+ const {inner,handle}= _terminalEls();
196
+ const next=_clampTerminalHeight(height);
197
+ TERMINAL_UI.height=next;
198
+ if(inner)inner.style.setProperty('--composer-terminal-height',next+'px');
199
+ if(handle){
200
+ const bounds=_terminalHeightBounds();
201
+ handle.setAttribute('aria-valuemin',String(bounds.min));
202
+ handle.setAttribute('aria-valuemax',String(bounds.max));
203
+ handle.setAttribute('aria-valuenow',String(next));
204
+ }
205
+ if(TERMINAL_UI.open&&!TERMINAL_UI.collapsed){
206
+ _fitTerminal();
207
+ _syncTerminalTranscriptSpace(true);
208
+ }
209
+ return next;
210
+ }
211
+
212
+ function _resetTerminalHeightForViewport(){
213
+ const bounds=_terminalHeightBounds();
214
+ _applyTerminalHeight(TERMINAL_UI.height||bounds.defaultHeight);
215
+ }
216
+
217
+ function _startTerminalHeightResize(ev){
218
+ if(ev.pointerType==='touch')return;
219
+ const {inner,handle}= _terminalEls();
220
+ if(!inner||!handle)return;
221
+ ev.preventDefault();
222
+ TERMINAL_UI.resizing=true;
223
+ TERMINAL_UI.resizeStartY=ev.clientY;
224
+ TERMINAL_UI.resizeStartHeight=TERMINAL_UI.height||inner.getBoundingClientRect().height||_terminalHeightBounds().defaultHeight;
225
+ inner.classList.add('is-resizing');
226
+ try{handle.setPointerCapture(ev.pointerId);}catch(_){}
227
+ }
228
+
229
+ function _moveTerminalHeightResize(ev){
230
+ if(!TERMINAL_UI.resizing)return;
231
+ ev.preventDefault();
232
+ _applyTerminalHeight(TERMINAL_UI.resizeStartHeight+(TERMINAL_UI.resizeStartY-ev.clientY));
233
+ }
234
+
235
+ function _endTerminalHeightResize(ev){
236
+ if(!TERMINAL_UI.resizing)return;
237
+ TERMINAL_UI.resizing=false;
238
+ const {inner,handle}= _terminalEls();
239
+ if(inner)inner.classList.remove('is-resizing');
240
+ if(handle&&ev&&ev.pointerId!==undefined)try{handle.releasePointerCapture(ev.pointerId);}catch(_){}
241
+ _fitTerminal();
242
+ }
243
+
244
+ function _handleTerminalResizeKey(ev){
245
+ let delta=0;
246
+ if(ev.key==='ArrowUp')delta=16;
247
+ else if(ev.key==='ArrowDown')delta=-16;
248
+ else if(ev.key==='PageUp')delta=64;
249
+ else if(ev.key==='PageDown')delta=-64;
250
+ else if(ev.key==='Home'){
251
+ ev.preventDefault();
252
+ return _applyTerminalHeight(_terminalHeightBounds().min);
253
+ }
254
+ else if(ev.key==='End'){
255
+ ev.preventDefault();
256
+ return _applyTerminalHeight(_terminalHeightBounds().max);
257
+ }
258
+ else return;
259
+ ev.preventDefault();
260
+ _applyTerminalHeight((TERMINAL_UI.height||_terminalHeightBounds().defaultHeight)+delta);
261
+ }
262
+
263
+ function _initTerminalResizeHandle(){
264
+ if(TERMINAL_UI.resizeHandleReady)return;
265
+ const {handle}= _terminalEls();
266
+ if(!handle)return;
267
+ TERMINAL_UI.resizeHandleReady=true;
268
+ handle.addEventListener('pointerdown',_startTerminalHeightResize);
269
+ handle.addEventListener('pointermove',_moveTerminalHeightResize);
270
+ handle.addEventListener('pointerup',_endTerminalHeightResize);
271
+ handle.addEventListener('pointercancel',_endTerminalHeightResize);
272
+ handle.addEventListener('keydown',_handleTerminalResizeKey);
273
+ }
274
+
275
+ function _terminalMessagesEl(){
276
+ return document.getElementById('messages');
277
+ }
278
+
279
+ function _terminalIsMessagesNearBottom(el){
280
+ if(!el)return false;
281
+ return el.scrollHeight-el.scrollTop-el.clientHeight<150;
282
+ }
283
+
284
+ function _syncTerminalTranscriptSpace(open,opts){
285
+ opts=opts||{};
286
+ const messages=_terminalMessagesEl();
287
+ if(!messages)return;
288
+ const wasNearBottom=_terminalIsMessagesNearBottom(messages);
289
+ if(!open){
290
+ messages.classList.remove('terminal-open');
291
+ messages.classList.remove('terminal-collapsed');
292
+ messages.classList.remove('terminal-expanding-from-dock');
293
+ messages.style.removeProperty('--terminal-card-height');
294
+ messages.style.removeProperty('--terminal-dock-height');
295
+ if(wasNearBottom&&typeof scrollToBottom==='function')requestAnimationFrame(scrollToBottom);
296
+ return;
297
+ }
298
+ if(open==='collapsed'){
299
+ messages.classList.remove('terminal-open');
300
+ messages.classList.add('terminal-collapsed');
301
+ }else{
302
+ messages.classList.add('terminal-open');
303
+ messages.classList.remove('terminal-collapsed');
304
+ }
305
+ const measure=()=>{
306
+ if(!TERMINAL_UI.open)return;
307
+ const {panel,inner,dock}= _terminalEls();
308
+ const target=open==='collapsed'?(dock||panel):(inner||panel);
309
+ const h=target&&target.getBoundingClientRect().height;
310
+ if(h>0){
311
+ if(open==='collapsed')messages.style.setProperty('--terminal-dock-height',Math.ceil(h+24)+'px');
312
+ else messages.style.setProperty('--terminal-card-height',Math.ceil(h+24)+'px');
313
+ }
314
+ if(wasNearBottom&&typeof scrollToBottom==='function')scrollToBottom();
315
+ };
316
+ if(opts.immediate)measure();
317
+ requestAnimationFrame(measure);
318
+ setTimeout(measure,420);
319
+ }
320
+
321
+ function _fitTerminal(){
322
+ const term=TERMINAL_UI.term;
323
+ if(!term)return;
324
+ if(TERMINAL_UI.collapsed)return;
325
+ try{
326
+ if(TERMINAL_UI.fitAddon)TERMINAL_UI.fitAddon.fit();
327
+ }catch(_){}
328
+ _syncTerminalTranscriptSpace(true);
329
+ _scheduleTerminalResize();
330
+ }
331
+
332
+ function _setTerminalChromeState(state){
333
+ const {panel,inner,dock,workspace,dockWorkspace}= _terminalEls();
334
+ const composerWrap=$('composerWrap');
335
+ if(!panel)return;
336
+ const collapsed=state==='collapsed';
337
+ const expanded=state==='expanded';
338
+ if(composerWrap)composerWrap.classList.toggle('terminal-dock-visible',collapsed);
339
+ panel.hidden=!(collapsed||expanded);
340
+ panel.classList.toggle('is-open',expanded);
341
+ panel.classList.toggle('is-collapsed',collapsed);
342
+ if(inner)inner.setAttribute('aria-hidden',collapsed?'true':'false');
343
+ if(dock)dock.hidden=!collapsed;
344
+ const label=_terminalWorkspaceName();
345
+ if(workspace)workspace.textContent=label;
346
+ if(dockWorkspace)dockWorkspace.textContent=label;
347
+ }
348
+
349
+ function syncTerminalButton(){
350
+ const {toggle}= _terminalEls();
351
+ const currentSid=_terminalSessionId();
352
+ const currentWorkspace=S.session&&S.session.workspace;
353
+ if(TERMINAL_UI.open&&TERMINAL_UI.sessionId&&(currentSid!==TERMINAL_UI.sessionId||currentWorkspace!==TERMINAL_UI.workspace)){
354
+ closeComposerTerminal(TERMINAL_UI.sessionId);
355
+ }
356
+ if(!toggle)return;
357
+ const hasWorkspace=!!(S.session&&S.session.workspace);
358
+ toggle.disabled=!hasWorkspace;
359
+ toggle.classList.toggle('active',TERMINAL_UI.open);
360
+ toggle.setAttribute('aria-pressed',TERMINAL_UI.open?'true':'false');
361
+ toggle.title=hasWorkspace?(TERMINAL_UI.collapsed?t('terminal_expand'):t('terminal_open_title')):t('terminal_no_workspace_title');
362
+ toggle.setAttribute('aria-label',toggle.title);
363
+ }
364
+
365
+ function focusComposerTerminalInput(){
366
+ if(TERMINAL_UI.term)TERMINAL_UI.term.focus();
367
+ }
368
+
369
+ function _connectTerminalOutput(){
370
+ const sid=_terminalSessionId();
371
+ if(!sid)return;
372
+ if(TERMINAL_UI.source){
373
+ try{TERMINAL_UI.source.close();}catch(_){}
374
+ TERMINAL_UI.source=null;
375
+ }
376
+ const url=new URL('api/terminal/output',document.baseURI||location.href);
377
+ url.searchParams.set('session_id',sid);
378
+ const source=new EventSource(url.href,{withCredentials:true});
379
+ TERMINAL_UI.source=source;
380
+ source.addEventListener('output',ev=>{
381
+ if(TERMINAL_UI.source!==source)return;
382
+ let text='';
383
+ try{text=(JSON.parse(ev.data)||{}).text||'';}
384
+ catch(_){text=ev.data||'';}
385
+ if(TERMINAL_UI.term&&text)TERMINAL_UI.term.write(text);
386
+ });
387
+ source.addEventListener('terminal_closed',()=>{
388
+ if(TERMINAL_UI.source!==source)return;
389
+ if(TERMINAL_UI.term)TERMINAL_UI.term.writeln('\r\n[terminal closed]\r\n');
390
+ try{source.close();}catch(_){}
391
+ TERMINAL_UI.source=null;
392
+ setTimeout(()=>closeComposerTerminal(null,{skipApi:true}),260);
393
+ });
394
+ source.addEventListener('terminal_error',ev=>{
395
+ if(TERMINAL_UI.source!==source)return;
396
+ let msg=t('terminal_error');
397
+ try{msg=(JSON.parse(ev.data)||{}).error||msg;}catch(_){}
398
+ if(TERMINAL_UI.term)TERMINAL_UI.term.writeln('\r\n[terminal error] '+msg+'\r\n');
399
+ try{source.close();}catch(_){}
400
+ TERMINAL_UI.source=null;
401
+ });
402
+ }
403
+
404
+ async function _startComposerTerminal(restart=false){
405
+ const sid=_terminalSessionId();
406
+ if(!sid||!(S.session&&S.session.workspace)){
407
+ showToast(t('terminal_no_workspace_title'),2600,'warning');
408
+ syncTerminalButton();
409
+ return;
410
+ }
411
+ const term=_ensureXterm();
412
+ if(!term)return;
413
+ _fitTerminal();
414
+ const dims=_terminalDimensions();
415
+ await api('/api/terminal/start',{method:'POST',body:JSON.stringify({
416
+ session_id:sid,
417
+ rows:dims.rows,
418
+ cols:dims.cols,
419
+ restart:!!restart,
420
+ })});
421
+ TERMINAL_UI.sessionId=sid;
422
+ TERMINAL_UI.workspace=S.session&&S.session.workspace||null;
423
+ TERMINAL_UI.typedLine='';
424
+ _connectTerminalOutput();
425
+ _resizeComposerTerminal();
426
+ }
427
+
428
+ async function toggleComposerTerminal(force){
429
+ const next=typeof force==='boolean'?force:!TERMINAL_UI.open;
430
+ if(next){
431
+ if(TERMINAL_UI.open){
432
+ if(TERMINAL_UI.collapsed)expandComposerTerminal();
433
+ else focusComposerTerminalInput();
434
+ return;
435
+ }
436
+ const {panel,inner}= _terminalEls();
437
+ const messages=_terminalMessagesEl();
438
+ if(!panel)return;
439
+ clearTimeout(TERMINAL_UI.closeTimer);
440
+ _initTerminalResizeHandle();
441
+ _resetTerminalHeightForViewport();
442
+ if(messages)messages.classList.add('terminal-expanding-from-dock');
443
+ _setTerminalChromeState('expanded');
444
+ TERMINAL_UI.open=true;
445
+ TERMINAL_UI.collapsed=false;
446
+ _syncTerminalTranscriptSpace(true,{immediate:true});
447
+ if(messages)void messages.offsetHeight;
448
+ requestAnimationFrame(()=>{
449
+ panel.classList.add('is-open');
450
+ window.setTimeout(_fitTerminal,80);
451
+ setTimeout(()=>{
452
+ if(messages)messages.classList.remove('terminal-expanding-from-dock');
453
+ },120);
454
+ });
455
+ syncTerminalButton();
456
+ if(!TERMINAL_UI.resizeObserver&&window.ResizeObserver){
457
+ TERMINAL_UI.resizeObserver=new ResizeObserver(()=>_fitTerminal());
458
+ TERMINAL_UI.resizeObserver.observe(inner||panel);
459
+ }
460
+ try{
461
+ await _startComposerTerminal(false);
462
+ focusComposerTerminalInput();
463
+ }catch(e){
464
+ showToast(t('terminal_start_failed')+e.message,3200,'error');
465
+ }
466
+ }else{
467
+ await closeComposerTerminal();
468
+ }
469
+ }
470
+
471
+ function collapseComposerTerminal(){
472
+ if(!TERMINAL_UI.open||TERMINAL_UI.collapsed)return;
473
+ TERMINAL_UI.collapsed=true;
474
+ _setTerminalChromeState('collapsed');
475
+ _syncTerminalTranscriptSpace('collapsed');
476
+ syncTerminalButton();
477
+ }
478
+
479
+ function expandComposerTerminal(){
480
+ if(!TERMINAL_UI.open)return;
481
+ const {panel}= _terminalEls();
482
+ const messages=_terminalMessagesEl();
483
+ TERMINAL_UI.collapsed=false;
484
+ clearTimeout(TERMINAL_UI.closeTimer);
485
+ if(panel)panel.classList.add('is-expanding-from-dock');
486
+ if(messages)messages.classList.add('terminal-expanding-from-dock');
487
+ _syncTerminalTranscriptSpace(true,{immediate:true});
488
+ if(messages)void messages.offsetHeight;
489
+ _setTerminalChromeState('expanded');
490
+ _resetTerminalHeightForViewport();
491
+ requestAnimationFrame(()=>{
492
+ _fitTerminal();
493
+ focusComposerTerminalInput();
494
+ setTimeout(()=>{
495
+ if(panel)panel.classList.remove('is-expanding-from-dock');
496
+ if(messages)messages.classList.remove('terminal-expanding-from-dock');
497
+ },120);
498
+ });
499
+ syncTerminalButton();
500
+ }
501
+
502
+ function _disposeXterm(){
503
+ if(TERMINAL_UI.term){
504
+ try{TERMINAL_UI.term.dispose();}catch(_){}
505
+ }
506
+ TERMINAL_UI.term=null;
507
+ TERMINAL_UI.fitAddon=null;
508
+ TERMINAL_UI.typedLine='';
509
+ const {surface}= _terminalEls();
510
+ if(surface)surface.textContent='';
511
+ }
512
+
513
+ async function closeComposerTerminal(sessionId,opts){
514
+ opts=opts||{};
515
+ const sid=sessionId||TERMINAL_UI.sessionId||_terminalSessionId();
516
+ if(TERMINAL_UI.source){
517
+ try{TERMINAL_UI.source.close();}catch(_){}
518
+ TERMINAL_UI.source=null;
519
+ }
520
+ if(sid&&!opts.skipApi){
521
+ api('/api/terminal/close',{method:'POST',body:JSON.stringify({session_id:sid})}).catch(()=>{});
522
+ }
523
+ const {panel}= _terminalEls();
524
+ if(panel){
525
+ panel.classList.remove('is-open','is-collapsed','is-expanding-from-dock');
526
+ _syncTerminalTranscriptSpace(false);
527
+ clearTimeout(TERMINAL_UI.closeTimer);
528
+ TERMINAL_UI.closeTimer=setTimeout(()=>{
529
+ if(!TERMINAL_UI.open)panel.hidden=true;
530
+ _disposeXterm();
531
+ },280);
532
+ }else{
533
+ _syncTerminalTranscriptSpace(false);
534
+ _disposeXterm();
535
+ }
536
+ TERMINAL_UI.open=false;
537
+ TERMINAL_UI.collapsed=false;
538
+ const composerWrap=$('composerWrap');
539
+ if(composerWrap)composerWrap.classList.remove('terminal-dock-visible');
540
+ TERMINAL_UI.sessionId=null;
541
+ TERMINAL_UI.workspace=null;
542
+ syncTerminalButton();
543
+ }
544
+
545
+ async function restartComposerTerminal(){
546
+ if(!TERMINAL_UI.open||TERMINAL_UI.collapsed)return;
547
+ if(TERMINAL_UI.source){
548
+ try{TERMINAL_UI.source.close();}catch(_){}
549
+ TERMINAL_UI.source=null;
550
+ }
551
+ if(TERMINAL_UI.term)TERMINAL_UI.term.reset();
552
+ try{await _startComposerTerminal(true);}
553
+ catch(e){showToast(t('terminal_start_failed')+e.message,3200,'error');}
554
+ }
555
+
556
+ function clearComposerTerminal(){
557
+ if(TERMINAL_UI.term)TERMINAL_UI.term.clear();
558
+ }
559
+
560
+ function _terminalBufferText(){
561
+ const term=TERMINAL_UI.term;
562
+ if(!term||!term.buffer)return '';
563
+ const buffer=term.buffer.active;
564
+ const lines=[];
565
+ for(let i=0;i<buffer.length;i++){
566
+ const line=buffer.getLine(i);
567
+ if(line)lines.push(line.translateToString(true));
568
+ }
569
+ return lines.join('\n').trim();
570
+ }
571
+
572
+ async function copyComposerTerminalOutput(){
573
+ try{
574
+ const selection=TERMINAL_UI.term&&TERMINAL_UI.term.getSelection?TERMINAL_UI.term.getSelection():'';
575
+ await navigator.clipboard.writeText(selection||_terminalBufferText());
576
+ showToast(t('copied'));
577
+ }catch(e){
578
+ showToast(t('terminal_copy_failed')+e.message,2600,'error');
579
+ }
580
+ }
581
+
582
+ async function submitComposerTerminalInput(ev){
583
+ if(ev)ev.preventDefault();
584
+ }
585
+
586
+ function _scheduleTerminalResize(){
587
+ clearTimeout(TERMINAL_UI.resizeTimer);
588
+ TERMINAL_UI.resizeTimer=setTimeout(_resizeComposerTerminal,120);
589
+ }
590
+
591
+ async function _resizeComposerTerminal(){
592
+ if(!TERMINAL_UI.open||TERMINAL_UI.collapsed)return;
593
+ const sid=TERMINAL_UI.sessionId||_terminalSessionId();
594
+ if(!sid)return;
595
+ const dims=_terminalDimensions();
596
+ try{
597
+ await api('/api/terminal/resize',{method:'POST',body:JSON.stringify({
598
+ session_id:sid,
599
+ rows:dims.rows,
600
+ cols:dims.cols,
601
+ })});
602
+ }catch(_){}
603
+ }
604
+
605
+ window.addEventListener('beforeunload',()=>{
606
+ if(TERMINAL_UI.source)try{TERMINAL_UI.source.close();}catch(_){}
607
+ if(TERMINAL_UI.sessionId){
608
+ const url=new URL('api/terminal/close',document.baseURI||location.href).href;
609
+ const body=JSON.stringify({session_id:TERMINAL_UI.sessionId});
610
+ try{
611
+ navigator.sendBeacon(url,new Blob([body],{type:'application/json'}));
612
+ }catch(_){
613
+ try{fetch(url,{method:'POST',credentials:'include',headers:{'Content-Type':'application/json'},body,keepalive:true});}catch(__){}
614
+ }
615
+ }
616
+ });
617
+
618
+ window.addEventListener('resize',()=>{
619
+ if(!TERMINAL_UI.open)return;
620
+ if(TERMINAL_UI.collapsed){
621
+ _syncTerminalTranscriptSpace('collapsed');
622
+ return;
623
+ }
624
+ _resetTerminalHeightForViewport();
625
+ });
626
+
627
+ if(window.MutationObserver){
628
+ new MutationObserver(syncComposerTerminalTheme).observe(document.documentElement,{
629
+ attributes:true,
630
+ attributeFilter:['class','data-skin'],
631
+ });
632
+ }