codex-autorunner 0.1.2__py3-none-any.whl → 1.1.0__py3-none-any.whl

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 (276) hide show
  1. codex_autorunner/__init__.py +12 -1
  2. codex_autorunner/__main__.py +4 -0
  3. codex_autorunner/agents/codex/harness.py +1 -1
  4. codex_autorunner/agents/opencode/client.py +68 -35
  5. codex_autorunner/agents/opencode/constants.py +3 -0
  6. codex_autorunner/agents/opencode/harness.py +6 -1
  7. codex_autorunner/agents/opencode/logging.py +21 -5
  8. codex_autorunner/agents/opencode/run_prompt.py +1 -0
  9. codex_autorunner/agents/opencode/runtime.py +176 -47
  10. codex_autorunner/agents/opencode/supervisor.py +36 -48
  11. codex_autorunner/agents/registry.py +155 -8
  12. codex_autorunner/api.py +25 -0
  13. codex_autorunner/bootstrap.py +22 -37
  14. codex_autorunner/cli.py +5 -1156
  15. codex_autorunner/codex_cli.py +20 -84
  16. codex_autorunner/core/__init__.py +4 -0
  17. codex_autorunner/core/about_car.py +49 -32
  18. codex_autorunner/core/adapter_utils.py +21 -0
  19. codex_autorunner/core/app_server_ids.py +59 -0
  20. codex_autorunner/core/app_server_logging.py +7 -3
  21. codex_autorunner/core/app_server_prompts.py +27 -260
  22. codex_autorunner/core/app_server_threads.py +26 -28
  23. codex_autorunner/core/app_server_utils.py +165 -0
  24. codex_autorunner/core/archive.py +349 -0
  25. codex_autorunner/core/codex_runner.py +12 -2
  26. codex_autorunner/core/config.py +587 -103
  27. codex_autorunner/core/docs.py +10 -2
  28. codex_autorunner/core/drafts.py +136 -0
  29. codex_autorunner/core/engine.py +1531 -866
  30. codex_autorunner/core/exceptions.py +4 -0
  31. codex_autorunner/core/flows/__init__.py +25 -0
  32. codex_autorunner/core/flows/controller.py +202 -0
  33. codex_autorunner/core/flows/definition.py +82 -0
  34. codex_autorunner/core/flows/models.py +88 -0
  35. codex_autorunner/core/flows/reasons.py +52 -0
  36. codex_autorunner/core/flows/reconciler.py +131 -0
  37. codex_autorunner/core/flows/runtime.py +382 -0
  38. codex_autorunner/core/flows/store.py +568 -0
  39. codex_autorunner/core/flows/transition.py +138 -0
  40. codex_autorunner/core/flows/ux_helpers.py +257 -0
  41. codex_autorunner/core/flows/worker_process.py +242 -0
  42. codex_autorunner/core/git_utils.py +62 -0
  43. codex_autorunner/core/hub.py +136 -16
  44. codex_autorunner/core/locks.py +4 -0
  45. codex_autorunner/core/notifications.py +14 -2
  46. codex_autorunner/core/ports/__init__.py +28 -0
  47. codex_autorunner/core/ports/agent_backend.py +150 -0
  48. codex_autorunner/core/ports/backend_orchestrator.py +41 -0
  49. codex_autorunner/core/ports/run_event.py +91 -0
  50. codex_autorunner/core/prompt.py +15 -7
  51. codex_autorunner/core/redaction.py +29 -0
  52. codex_autorunner/core/review_context.py +5 -8
  53. codex_autorunner/core/run_index.py +6 -0
  54. codex_autorunner/core/runner_process.py +5 -2
  55. codex_autorunner/core/state.py +0 -88
  56. codex_autorunner/core/state_roots.py +57 -0
  57. codex_autorunner/core/supervisor_protocol.py +15 -0
  58. codex_autorunner/core/supervisor_utils.py +67 -0
  59. codex_autorunner/core/text_delta_coalescer.py +54 -0
  60. codex_autorunner/core/ticket_linter_cli.py +201 -0
  61. codex_autorunner/core/ticket_manager_cli.py +432 -0
  62. codex_autorunner/core/update.py +24 -16
  63. codex_autorunner/core/update_paths.py +28 -0
  64. codex_autorunner/core/update_runner.py +2 -0
  65. codex_autorunner/core/usage.py +164 -12
  66. codex_autorunner/core/utils.py +120 -11
  67. codex_autorunner/discovery.py +2 -4
  68. codex_autorunner/flows/review/__init__.py +17 -0
  69. codex_autorunner/{core/review.py → flows/review/service.py} +15 -10
  70. codex_autorunner/flows/ticket_flow/__init__.py +3 -0
  71. codex_autorunner/flows/ticket_flow/definition.py +98 -0
  72. codex_autorunner/integrations/agents/__init__.py +17 -0
  73. codex_autorunner/integrations/agents/backend_orchestrator.py +284 -0
  74. codex_autorunner/integrations/agents/codex_adapter.py +90 -0
  75. codex_autorunner/integrations/agents/codex_backend.py +448 -0
  76. codex_autorunner/integrations/agents/opencode_adapter.py +108 -0
  77. codex_autorunner/integrations/agents/opencode_backend.py +598 -0
  78. codex_autorunner/integrations/agents/runner.py +91 -0
  79. codex_autorunner/integrations/agents/wiring.py +271 -0
  80. codex_autorunner/integrations/app_server/client.py +583 -152
  81. codex_autorunner/integrations/app_server/env.py +2 -107
  82. codex_autorunner/{core/app_server_events.py → integrations/app_server/event_buffer.py} +15 -8
  83. codex_autorunner/integrations/app_server/supervisor.py +59 -33
  84. codex_autorunner/integrations/telegram/adapter.py +204 -165
  85. codex_autorunner/integrations/telegram/api_schemas.py +120 -0
  86. codex_autorunner/integrations/telegram/config.py +221 -0
  87. codex_autorunner/integrations/telegram/constants.py +17 -2
  88. codex_autorunner/integrations/telegram/dispatch.py +17 -0
  89. codex_autorunner/integrations/telegram/doctor.py +47 -0
  90. codex_autorunner/integrations/telegram/handlers/callbacks.py +7 -4
  91. codex_autorunner/integrations/telegram/handlers/commands/__init__.py +2 -0
  92. codex_autorunner/integrations/telegram/handlers/commands/execution.py +53 -57
  93. codex_autorunner/integrations/telegram/handlers/commands/files.py +2 -6
  94. codex_autorunner/integrations/telegram/handlers/commands/flows.py +1364 -0
  95. codex_autorunner/integrations/telegram/handlers/commands/formatting.py +1 -1
  96. codex_autorunner/integrations/telegram/handlers/commands/github.py +41 -582
  97. codex_autorunner/integrations/telegram/handlers/commands/workspace.py +8 -8
  98. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +137 -478
  99. codex_autorunner/integrations/telegram/handlers/commands_spec.py +17 -4
  100. codex_autorunner/integrations/telegram/handlers/messages.py +121 -9
  101. codex_autorunner/integrations/telegram/handlers/selections.py +61 -1
  102. codex_autorunner/integrations/telegram/helpers.py +111 -16
  103. codex_autorunner/integrations/telegram/outbox.py +208 -37
  104. codex_autorunner/integrations/telegram/progress_stream.py +3 -10
  105. codex_autorunner/integrations/telegram/service.py +221 -42
  106. codex_autorunner/integrations/telegram/state.py +100 -2
  107. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +611 -0
  108. codex_autorunner/integrations/telegram/transport.py +39 -4
  109. codex_autorunner/integrations/telegram/trigger_mode.py +53 -0
  110. codex_autorunner/manifest.py +2 -0
  111. codex_autorunner/plugin_api.py +22 -0
  112. codex_autorunner/routes/__init__.py +37 -67
  113. codex_autorunner/routes/agents.py +2 -137
  114. codex_autorunner/routes/analytics.py +3 -0
  115. codex_autorunner/routes/app_server.py +2 -131
  116. codex_autorunner/routes/base.py +2 -624
  117. codex_autorunner/routes/file_chat.py +7 -0
  118. codex_autorunner/routes/flows.py +7 -0
  119. codex_autorunner/routes/messages.py +7 -0
  120. codex_autorunner/routes/repos.py +2 -196
  121. codex_autorunner/routes/review.py +2 -147
  122. codex_autorunner/routes/sessions.py +2 -175
  123. codex_autorunner/routes/settings.py +2 -168
  124. codex_autorunner/routes/shared.py +2 -275
  125. codex_autorunner/routes/system.py +4 -188
  126. codex_autorunner/routes/usage.py +3 -0
  127. codex_autorunner/routes/voice.py +2 -119
  128. codex_autorunner/routes/workspace.py +3 -0
  129. codex_autorunner/server.py +3 -2
  130. codex_autorunner/static/agentControls.js +41 -11
  131. codex_autorunner/static/agentEvents.js +248 -0
  132. codex_autorunner/static/app.js +35 -24
  133. codex_autorunner/static/archive.js +826 -0
  134. codex_autorunner/static/archiveApi.js +37 -0
  135. codex_autorunner/static/autoRefresh.js +36 -8
  136. codex_autorunner/static/bootstrap.js +1 -0
  137. codex_autorunner/static/bus.js +1 -0
  138. codex_autorunner/static/cache.js +1 -0
  139. codex_autorunner/static/constants.js +20 -4
  140. codex_autorunner/static/dashboard.js +344 -325
  141. codex_autorunner/static/diffRenderer.js +37 -0
  142. codex_autorunner/static/docChatCore.js +324 -0
  143. codex_autorunner/static/docChatStorage.js +65 -0
  144. codex_autorunner/static/docChatVoice.js +65 -0
  145. codex_autorunner/static/docEditor.js +133 -0
  146. codex_autorunner/static/env.js +1 -0
  147. codex_autorunner/static/eventSummarizer.js +166 -0
  148. codex_autorunner/static/fileChat.js +182 -0
  149. codex_autorunner/static/health.js +155 -0
  150. codex_autorunner/static/hub.js +126 -185
  151. codex_autorunner/static/index.html +839 -863
  152. codex_autorunner/static/liveUpdates.js +1 -0
  153. codex_autorunner/static/loader.js +1 -0
  154. codex_autorunner/static/messages.js +873 -0
  155. codex_autorunner/static/mobileCompact.js +2 -1
  156. codex_autorunner/static/preserve.js +17 -0
  157. codex_autorunner/static/settings.js +149 -217
  158. codex_autorunner/static/smartRefresh.js +52 -0
  159. codex_autorunner/static/styles.css +8850 -3876
  160. codex_autorunner/static/tabs.js +175 -11
  161. codex_autorunner/static/terminal.js +32 -0
  162. codex_autorunner/static/terminalManager.js +34 -59
  163. codex_autorunner/static/ticketChatActions.js +333 -0
  164. codex_autorunner/static/ticketChatEvents.js +16 -0
  165. codex_autorunner/static/ticketChatStorage.js +16 -0
  166. codex_autorunner/static/ticketChatStream.js +264 -0
  167. codex_autorunner/static/ticketEditor.js +844 -0
  168. codex_autorunner/static/ticketVoice.js +9 -0
  169. codex_autorunner/static/tickets.js +1988 -0
  170. codex_autorunner/static/utils.js +43 -3
  171. codex_autorunner/static/voice.js +1 -0
  172. codex_autorunner/static/workspace.js +765 -0
  173. codex_autorunner/static/workspaceApi.js +53 -0
  174. codex_autorunner/static/workspaceFileBrowser.js +504 -0
  175. codex_autorunner/surfaces/__init__.py +5 -0
  176. codex_autorunner/surfaces/cli/__init__.py +6 -0
  177. codex_autorunner/surfaces/cli/cli.py +1224 -0
  178. codex_autorunner/surfaces/cli/codex_cli.py +20 -0
  179. codex_autorunner/surfaces/telegram/__init__.py +3 -0
  180. codex_autorunner/surfaces/web/__init__.py +1 -0
  181. codex_autorunner/surfaces/web/app.py +2019 -0
  182. codex_autorunner/surfaces/web/hub_jobs.py +192 -0
  183. codex_autorunner/surfaces/web/middleware.py +587 -0
  184. codex_autorunner/surfaces/web/pty_session.py +370 -0
  185. codex_autorunner/surfaces/web/review.py +6 -0
  186. codex_autorunner/surfaces/web/routes/__init__.py +78 -0
  187. codex_autorunner/surfaces/web/routes/agents.py +138 -0
  188. codex_autorunner/surfaces/web/routes/analytics.py +277 -0
  189. codex_autorunner/surfaces/web/routes/app_server.py +132 -0
  190. codex_autorunner/surfaces/web/routes/archive.py +357 -0
  191. codex_autorunner/surfaces/web/routes/base.py +615 -0
  192. codex_autorunner/surfaces/web/routes/file_chat.py +836 -0
  193. codex_autorunner/surfaces/web/routes/flows.py +1164 -0
  194. codex_autorunner/surfaces/web/routes/messages.py +459 -0
  195. codex_autorunner/surfaces/web/routes/repos.py +197 -0
  196. codex_autorunner/surfaces/web/routes/review.py +148 -0
  197. codex_autorunner/surfaces/web/routes/sessions.py +176 -0
  198. codex_autorunner/surfaces/web/routes/settings.py +169 -0
  199. codex_autorunner/surfaces/web/routes/shared.py +280 -0
  200. codex_autorunner/surfaces/web/routes/system.py +196 -0
  201. codex_autorunner/surfaces/web/routes/usage.py +89 -0
  202. codex_autorunner/surfaces/web/routes/voice.py +120 -0
  203. codex_autorunner/surfaces/web/routes/workspace.py +271 -0
  204. codex_autorunner/surfaces/web/runner_manager.py +25 -0
  205. codex_autorunner/surfaces/web/schemas.py +417 -0
  206. codex_autorunner/surfaces/web/static_assets.py +490 -0
  207. codex_autorunner/surfaces/web/static_refresh.py +86 -0
  208. codex_autorunner/surfaces/web/terminal_sessions.py +78 -0
  209. codex_autorunner/tickets/__init__.py +27 -0
  210. codex_autorunner/tickets/agent_pool.py +399 -0
  211. codex_autorunner/tickets/files.py +89 -0
  212. codex_autorunner/tickets/frontmatter.py +55 -0
  213. codex_autorunner/tickets/lint.py +102 -0
  214. codex_autorunner/tickets/models.py +97 -0
  215. codex_autorunner/tickets/outbox.py +244 -0
  216. codex_autorunner/tickets/replies.py +179 -0
  217. codex_autorunner/tickets/runner.py +881 -0
  218. codex_autorunner/tickets/spec_ingest.py +77 -0
  219. codex_autorunner/web/__init__.py +5 -1
  220. codex_autorunner/web/app.py +2 -1771
  221. codex_autorunner/web/hub_jobs.py +2 -191
  222. codex_autorunner/web/middleware.py +2 -587
  223. codex_autorunner/web/pty_session.py +2 -369
  224. codex_autorunner/web/runner_manager.py +2 -24
  225. codex_autorunner/web/schemas.py +2 -396
  226. codex_autorunner/web/static_assets.py +4 -484
  227. codex_autorunner/web/static_refresh.py +2 -85
  228. codex_autorunner/web/terminal_sessions.py +2 -77
  229. codex_autorunner/workspace/__init__.py +40 -0
  230. codex_autorunner/workspace/paths.py +335 -0
  231. codex_autorunner-1.1.0.dist-info/METADATA +154 -0
  232. codex_autorunner-1.1.0.dist-info/RECORD +308 -0
  233. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/WHEEL +1 -1
  234. codex_autorunner/agents/execution/policy.py +0 -292
  235. codex_autorunner/agents/factory.py +0 -52
  236. codex_autorunner/agents/orchestrator.py +0 -358
  237. codex_autorunner/core/doc_chat.py +0 -1446
  238. codex_autorunner/core/snapshot.py +0 -580
  239. codex_autorunner/integrations/github/chatops.py +0 -268
  240. codex_autorunner/integrations/github/pr_flow.py +0 -1314
  241. codex_autorunner/routes/docs.py +0 -381
  242. codex_autorunner/routes/github.py +0 -327
  243. codex_autorunner/routes/runs.py +0 -250
  244. codex_autorunner/spec_ingest.py +0 -812
  245. codex_autorunner/static/docChatActions.js +0 -287
  246. codex_autorunner/static/docChatEvents.js +0 -300
  247. codex_autorunner/static/docChatRender.js +0 -205
  248. codex_autorunner/static/docChatStream.js +0 -361
  249. codex_autorunner/static/docs.js +0 -20
  250. codex_autorunner/static/docsClipboard.js +0 -69
  251. codex_autorunner/static/docsCrud.js +0 -257
  252. codex_autorunner/static/docsDocUpdates.js +0 -62
  253. codex_autorunner/static/docsDrafts.js +0 -16
  254. codex_autorunner/static/docsElements.js +0 -69
  255. codex_autorunner/static/docsInit.js +0 -285
  256. codex_autorunner/static/docsParse.js +0 -160
  257. codex_autorunner/static/docsSnapshot.js +0 -87
  258. codex_autorunner/static/docsSpecIngest.js +0 -263
  259. codex_autorunner/static/docsState.js +0 -127
  260. codex_autorunner/static/docsThreadRegistry.js +0 -44
  261. codex_autorunner/static/docsUi.js +0 -153
  262. codex_autorunner/static/docsVoice.js +0 -56
  263. codex_autorunner/static/github.js +0 -504
  264. codex_autorunner/static/logs.js +0 -678
  265. codex_autorunner/static/review.js +0 -157
  266. codex_autorunner/static/runs.js +0 -418
  267. codex_autorunner/static/snapshot.js +0 -124
  268. codex_autorunner/static/state.js +0 -94
  269. codex_autorunner/static/todoPreview.js +0 -27
  270. codex_autorunner/workspace.py +0 -16
  271. codex_autorunner-0.1.2.dist-info/METADATA +0 -249
  272. codex_autorunner-0.1.2.dist-info/RECORD +0 -222
  273. /codex_autorunner/{routes → surfaces/web/routes}/terminal_images.py +0 -0
  274. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/entry_points.txt +0 -0
  275. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/licenses/LICENSE +0 -0
  276. {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,41 +1,205 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
1
2
  import { publish } from "./bus.js";
2
- import { getUrlParams, updateUrlParams } from "./utils.js";
3
+ import { escapeHtml, getUrlParams, updateUrlParams } from "./utils.js";
3
4
  const tabs = [];
4
- export function registerTab(id, label) {
5
- tabs.push({ id, label });
5
+ const hamburgerActions = [];
6
+ let hamburgerMenuOpen = false;
7
+ let hamburgerMenuEl = null;
8
+ let hamburgerBtnEl = null;
9
+ let hamburgerBackdropEl = null;
10
+ export function registerTab(id, label, opts = {}) {
11
+ tabs.push({ id, label, hidden: Boolean(opts.hidden), menuTab: Boolean(opts.menuTab), icon: opts.icon });
6
12
  }
7
- export function initTabs(defaultTab = "dashboard") {
13
+ export function registerHamburgerAction(id, label, icon, onClick) {
14
+ hamburgerActions.push({ id, label, icon, onClick });
15
+ }
16
+ let setActivePanelFn = null;
17
+ let pendingActivate = null;
18
+ export function activateTab(id) {
19
+ if (setActivePanelFn) {
20
+ setActivePanelFn(id);
21
+ }
22
+ else {
23
+ pendingActivate = id;
24
+ }
25
+ }
26
+ function closeHamburgerMenu() {
27
+ if (!hamburgerMenuOpen)
28
+ return;
29
+ hamburgerMenuOpen = false;
30
+ hamburgerMenuEl?.classList.remove("open");
31
+ hamburgerBtnEl?.classList.remove("active");
32
+ hamburgerBackdropEl?.classList.remove("open");
33
+ }
34
+ function toggleHamburgerMenu() {
35
+ hamburgerMenuOpen = !hamburgerMenuOpen;
36
+ hamburgerMenuEl?.classList.toggle("open", hamburgerMenuOpen);
37
+ hamburgerBtnEl?.classList.toggle("active", hamburgerMenuOpen);
38
+ hamburgerBackdropEl?.classList.toggle("open", hamburgerMenuOpen);
39
+ }
40
+ function updateHamburgerActiveState(activeTabId) {
41
+ if (!hamburgerMenuEl)
42
+ return;
43
+ const items = hamburgerMenuEl.querySelectorAll(".hamburger-item[data-target]");
44
+ items.forEach((item) => {
45
+ const target = item.dataset.target;
46
+ item.classList.toggle("active", target === activeTabId);
47
+ });
48
+ // Also update hamburger button active state if a menu tab is active
49
+ const isMenuTabActive = tabs.some((t) => t.menuTab && t.id === activeTabId);
50
+ hamburgerBtnEl?.classList.toggle("has-active", isMenuTabActive);
51
+ }
52
+ export function initTabs(defaultTab = "analytics") {
8
53
  const container = document.querySelector(".tabs");
54
+ const navBar = document.querySelector(".nav-bar");
9
55
  if (!container)
10
56
  return;
11
57
  container.innerHTML = "";
12
58
  const panels = document.querySelectorAll(".panel");
13
59
  const setActivePanel = (id) => {
14
60
  panels.forEach((p) => p.classList.toggle("active", p.id === id));
61
+ // Update primary tab buttons
15
62
  const buttons = container.querySelectorAll(".tab");
16
63
  buttons.forEach((btn) => btn.classList.toggle("active", btn.dataset.target === id));
64
+ // Update hamburger menu items
65
+ updateHamburgerActiveState(id);
17
66
  updateUrlParams({ tab: id });
18
67
  publish("tab:change", id);
19
68
  };
20
- tabs.forEach(tab => {
69
+ setActivePanelFn = setActivePanel;
70
+ // Separate primary tabs from menu tabs
71
+ const primaryTabs = tabs.filter((t) => !t.hidden && !t.menuTab);
72
+ const menuTabs = tabs.filter((t) => !t.hidden && t.menuTab);
73
+ // Render primary tabs
74
+ primaryTabs.forEach(tab => {
21
75
  const btn = document.createElement("button");
22
76
  btn.className = "tab";
23
77
  btn.dataset.target = tab.id;
24
- btn.textContent = tab.label;
78
+ btn.innerHTML = `
79
+ <span class="tab-label">${escapeHtml(tab.label)}</span>
80
+ <span class="badge hidden" id="tab-badge-${tab.id}"></span>
81
+ `;
25
82
  btn.addEventListener("click", () => setActivePanel(tab.id));
26
83
  container.appendChild(btn);
27
84
  });
85
+ // Create hamburger menu if there are menu tabs or actions
86
+ if (menuTabs.length > 0 || hamburgerActions.length > 0) {
87
+ const wrapper = document.createElement("div");
88
+ wrapper.className = "hamburger-wrapper";
89
+ // Hamburger button
90
+ const btn = document.createElement("button");
91
+ btn.className = "hamburger-btn";
92
+ btn.setAttribute("aria-label", "More options");
93
+ btn.setAttribute("aria-expanded", "false");
94
+ btn.innerHTML = `
95
+ <span class="hamburger-icon">
96
+ <span></span>
97
+ <span></span>
98
+ <span></span>
99
+ </span>
100
+ `;
101
+ hamburgerBtnEl = btn;
102
+ // Hamburger menu dropdown
103
+ const menu = document.createElement("div");
104
+ menu.className = "hamburger-menu";
105
+ menu.setAttribute("role", "menu");
106
+ hamburgerMenuEl = menu;
107
+ // Add menu tab items
108
+ menuTabs.forEach((tab) => {
109
+ const item = document.createElement("button");
110
+ item.className = "hamburger-item";
111
+ item.dataset.target = tab.id;
112
+ item.setAttribute("role", "menuitem");
113
+ const iconHtml = tab.icon ? `<span class="hamburger-item-icon">${tab.icon}</span>` : "";
114
+ item.innerHTML = `${iconHtml}<span>${escapeHtml(tab.label)}</span>`;
115
+ item.addEventListener("click", () => {
116
+ setActivePanel(tab.id);
117
+ closeHamburgerMenu();
118
+ });
119
+ menu.appendChild(item);
120
+ });
121
+ // Add divider if there are both tabs and actions
122
+ if (menuTabs.length > 0 && hamburgerActions.length > 0) {
123
+ const divider = document.createElement("div");
124
+ divider.className = "hamburger-divider";
125
+ menu.appendChild(divider);
126
+ }
127
+ // Add action items (like Settings)
128
+ hamburgerActions.forEach((action) => {
129
+ const item = document.createElement("button");
130
+ item.className = "hamburger-item";
131
+ item.dataset.action = action.id;
132
+ item.setAttribute("role", "menuitem");
133
+ const iconHtml = action.icon ? `<span class="hamburger-item-icon">${action.icon}</span>` : "";
134
+ item.innerHTML = `${iconHtml}<span>${escapeHtml(action.label)}</span>`;
135
+ item.addEventListener("click", () => {
136
+ action.onClick();
137
+ closeHamburgerMenu();
138
+ });
139
+ menu.appendChild(item);
140
+ });
141
+ // Mobile backdrop - appended to body for proper z-index stacking
142
+ const backdrop = document.createElement("div");
143
+ backdrop.className = "hamburger-backdrop";
144
+ backdrop.addEventListener("click", closeHamburgerMenu);
145
+ hamburgerBackdropEl = backdrop;
146
+ document.body.appendChild(backdrop);
147
+ // Append menu to body for mobile z-index stacking (above backdrop)
148
+ // On mobile, the nav-bar has z-index:100 which creates a stacking context
149
+ // that would trap the menu below the backdrop (z-index:1999)
150
+ document.body.appendChild(menu);
151
+ // Toggle menu on button click
152
+ const toggleHandler = (e) => {
153
+ e.stopPropagation();
154
+ // Prevent ghost clicks on touch devices
155
+ if (e.type === "touchend") {
156
+ e.preventDefault();
157
+ }
158
+ toggleHamburgerMenu();
159
+ btn.setAttribute("aria-expanded", String(hamburgerMenuOpen));
160
+ };
161
+ btn.addEventListener("click", toggleHandler);
162
+ btn.addEventListener("touchend", toggleHandler);
163
+ // Close menu on outside click (check both wrapper and menu since menu is in body)
164
+ document.addEventListener("click", (e) => {
165
+ if (hamburgerMenuOpen && !wrapper.contains(e.target) && !menu.contains(e.target)) {
166
+ closeHamburgerMenu();
167
+ }
168
+ });
169
+ // Close menu on Escape
170
+ document.addEventListener("keydown", (e) => {
171
+ if (e.key === "Escape" && hamburgerMenuOpen) {
172
+ closeHamburgerMenu();
173
+ hamburgerBtnEl?.focus();
174
+ }
175
+ });
176
+ wrapper.appendChild(btn);
177
+ // Insert hamburger after tabs or at the end of nav bar
178
+ const navActions = navBar?.querySelector(".nav-actions");
179
+ if (navActions) {
180
+ navBar?.insertBefore(wrapper, navActions);
181
+ }
182
+ else {
183
+ navBar?.appendChild(wrapper);
184
+ }
185
+ }
28
186
  const params = getUrlParams();
29
187
  const requested = params.get("tab");
30
- const initialTab = tabs.some((t) => t.id === requested)
188
+ const allVisibleTabs = tabs.filter((t) => !t.hidden);
189
+ const initialTab = allVisibleTabs.some((t) => t.id === requested)
31
190
  ? requested
32
- : tabs.some((t) => t.id === defaultTab)
191
+ : allVisibleTabs.some((t) => t.id === defaultTab)
33
192
  ? defaultTab
34
- : tabs[0]?.id;
193
+ : allVisibleTabs[0]?.id;
35
194
  if (initialTab) {
36
195
  setActivePanel(initialTab);
37
196
  }
38
- else if (tabs.length > 0) {
39
- setActivePanel(tabs[0].id);
197
+ else if (allVisibleTabs.length > 0) {
198
+ setActivePanel(allVisibleTabs[0].id);
199
+ }
200
+ if (pendingActivate && allVisibleTabs.some((t) => t.id === pendingActivate)) {
201
+ const id = pendingActivate;
202
+ pendingActivate = null;
203
+ setActivePanel(id);
40
204
  }
41
205
  }
@@ -1,12 +1,44 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
1
2
  import { TerminalManager } from "./terminalManager.js";
3
+ import { refreshAgentControls } from "./agentControls.js";
4
+ import { subscribe } from "./bus.js";
5
+ import { isRepoHealthy } from "./health.js";
2
6
  let terminalManager = null;
7
+ let terminalHealthRefreshInitialized = false;
3
8
  export function getTerminalManager() {
4
9
  return terminalManager;
5
10
  }
6
11
  export function initTerminal() {
7
12
  if (terminalManager) {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ if (typeof terminalManager.fit === "function") {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ terminalManager.fit();
17
+ }
8
18
  return;
9
19
  }
10
20
  terminalManager = new TerminalManager();
11
21
  terminalManager.init();
22
+ initTerminalHealthRefresh();
23
+ // Ensure terminal is resized to fit container after initialization
24
+ if (terminalManager) {
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ if (typeof terminalManager.fit === "function") {
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ terminalManager.fit();
29
+ }
30
+ }
31
+ }
32
+ function initTerminalHealthRefresh() {
33
+ if (terminalHealthRefreshInitialized)
34
+ return;
35
+ terminalHealthRefreshInitialized = true;
36
+ subscribe("repo:health", (payload) => {
37
+ const status = payload?.status || "";
38
+ if (status !== "ok" && status !== "degraded")
39
+ return;
40
+ if (!isRepoHealthy())
41
+ return;
42
+ void refreshAgentControls({ reason: "background" });
43
+ });
12
44
  }
@@ -1,3 +1,4 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
1
2
  import { api, flash, buildWsUrl, getAuthToken, isMobileViewport } from "./utils.js";
2
3
  import { getSelectedAgent, getSelectedModel, getSelectedReasoning, initAgentControls, } from "./agentControls.js";
3
4
  function base64UrlEncode(value) {
@@ -44,21 +45,7 @@ const XTERM_COLOR_MODE_PALETTE_16 = 0x01000000;
44
45
  const XTERM_COLOR_MODE_PALETTE_256 = 0x02000000;
45
46
  const XTERM_COLOR_MODE_RGB = 0x03000000;
46
47
  const CAR_CONTEXT_HOOK_ID = "car_context";
47
- const GITHUB_CONTEXT_HOOK_ID = "github_context";
48
- const CAR_CONTEXT_KEYWORDS = [
49
- "car",
50
- "codex",
51
- "todo",
52
- "progress",
53
- "opinions",
54
- "spec",
55
- "summary",
56
- "autorunner",
57
- "work docs",
58
- ];
59
- const GITHUB_LINK_RE = /https?:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(?:issues|pull)\/\d+(?:[/?#][^\s]*)?/i;
60
- const CAR_CONTEXT_HINT_TEXT = "Context: read .codex-autorunner/ABOUT_CAR.md for repo-specific rules.";
61
- const CAR_CONTEXT_HINT = wrapInjectedContext(CAR_CONTEXT_HINT_TEXT);
48
+ const CAR_CONTEXT_HINT = wrapInjectedContext(CONSTANTS.PROMPTS.CAR_CONTEXT_HINT);
62
49
  const VOICE_TRANSCRIPT_DISCLAIMER_TEXT = CONSTANTS.PROMPTS?.VOICE_TRANSCRIPT_DISCLAIMER ||
63
50
  "Note: transcribed from user voice. If confusing or possibly inaccurate and you cannot infer the intention please clarify before proceeding.";
64
51
  const INJECTED_CONTEXT_TAG_RE = /<injected context>/i;
@@ -360,7 +347,6 @@ export class TerminalManager {
360
347
  this.lastAltScrollbackSize = 0;
361
348
  this.transcriptResetForConnect = false;
362
349
  this._registerTextInputHook(this._buildCarContextHook());
363
- this._registerTextInputHook(this._buildGithubContextHook());
364
350
  // Bind methods that are used as callbacks
365
351
  this._handleResize = this._handleResize.bind(this);
366
352
  this._handleVoiceHotkeyDown = this._handleVoiceHotkeyDown.bind(this);
@@ -444,6 +430,20 @@ export class TerminalManager {
444
430
  this.connect({ mode: "attach" });
445
431
  }
446
432
  }
433
+ /**
434
+ * Force resize terminal to fit container
435
+ */
436
+ fit() {
437
+ if (this.fitAddon && this.term) {
438
+ try {
439
+ this.fitAddon.fit();
440
+ this._handleResize(); // Send resize to server
441
+ }
442
+ catch (e) {
443
+ // ignore
444
+ }
445
+ }
446
+ }
447
447
  /**
448
448
  * Set terminal status message
449
449
  */
@@ -621,12 +621,12 @@ export class TerminalManager {
621
621
  if (manager._hasTextInputHookFired(CAR_CONTEXT_HOOK_ID))
622
622
  return null;
623
623
  const lowered = text.toLowerCase();
624
- const hit = CAR_CONTEXT_KEYWORDS.some((kw) => lowered.includes(kw));
624
+ const hit = CONSTANTS.KEYWORDS.CAR_CONTEXT.some((kw) => lowered.includes(kw));
625
625
  if (!hit)
626
626
  return null;
627
627
  if (lowered.includes("about_car.md"))
628
628
  return null;
629
- if (text.includes(CAR_CONTEXT_HINT_TEXT) ||
629
+ if (text.includes(CONSTANTS.PROMPTS.CAR_CONTEXT_HINT) ||
630
630
  text.includes(CAR_CONTEXT_HINT)) {
631
631
  return null;
632
632
  }
@@ -637,43 +637,8 @@ export class TerminalManager {
637
637
  },
638
638
  };
639
639
  }
640
- _buildGithubContextHook() {
641
- return {
642
- id: GITHUB_CONTEXT_HOOK_ID,
643
- apply: async ({ text }) => {
644
- if (!text || !text.trim())
645
- return null;
646
- const match = text.match(GITHUB_LINK_RE);
647
- if (!match)
648
- return null;
649
- try {
650
- const res = await api("/api/github/context", {
651
- method: "POST",
652
- body: { url: match[0] },
653
- });
654
- if (!res || typeof res !== "object")
655
- return null;
656
- const injection = wrapInjectedContextIfNeeded(res.hint);
657
- const separator = text.endsWith("\n") ? "\n" : "\n\n";
658
- return { text: `${text}${separator}${injection}` };
659
- }
660
- catch (_err) {
661
- return null;
662
- }
663
- },
664
- };
665
- }
666
640
  async _loadTerminalIdleTimeout() {
667
- try {
668
- const data = await api(CONSTANTS.API.STATE_ENDPOINT);
669
- if (data &&
670
- typeof data === "object" && data !== null && "terminal_idle_timeout_seconds" in data) {
671
- this.terminalIdleTimeoutSeconds = data.terminal_idle_timeout_seconds;
672
- }
673
- }
674
- catch (_err) {
675
- // ignore
676
- }
641
+ // State endpoint removed - terminal idle timeout no longer loaded from /api/state
677
642
  }
678
643
  _getSessionStorageKey() {
679
644
  return `${SESSION_STORAGE_PREFIX}${this._getRepoStorageKey()}`;
@@ -1880,7 +1845,8 @@ export class TerminalManager {
1880
1845
  * Ensure xterm terminal is initialized
1881
1846
  */
1882
1847
  _ensureTerminal() {
1883
- if (!window.Terminal || !window.FitAddon) {
1848
+ const win = window;
1849
+ if (!win.Terminal || !win.FitAddon) {
1884
1850
  this._setStatus("xterm assets missing; reload or check /static/vendor");
1885
1851
  flash("xterm assets missing; reload the page", "error");
1886
1852
  return false;
@@ -1899,7 +1865,7 @@ export class TerminalManager {
1899
1865
  const container = document.getElementById("terminal-container");
1900
1866
  if (!container)
1901
1867
  return false;
1902
- this.term = new window.Terminal({
1868
+ this.term = new win.Terminal({
1903
1869
  convertEol: true,
1904
1870
  fontFamily: '"JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace',
1905
1871
  fontSize: this._getFontSize(),
@@ -1911,7 +1877,7 @@ export class TerminalManager {
1911
1877
  scrollback: this.transcriptMaxLines,
1912
1878
  theme: CONSTANTS.THEME.XTERM,
1913
1879
  });
1914
- this.fitAddon = new window.FitAddon.FitAddon();
1880
+ this.fitAddon = new win.FitAddon.FitAddon();
1915
1881
  this.term.loadAddon(this.fitAddon);
1916
1882
  this.term.open(container);
1917
1883
  this.term.write('Press "New" or "Resume" to launch Codex TUI...\r\n');
@@ -1920,6 +1886,13 @@ export class TerminalManager {
1920
1886
  this.term.onScroll(() => this._updateJumpBottomVisibility());
1921
1887
  this.term.onRender(() => this._scheduleMobileViewRender());
1922
1888
  this._updateJumpBottomVisibility();
1889
+ // Initial fit
1890
+ try {
1891
+ this.fitAddon.fit();
1892
+ }
1893
+ catch (e) {
1894
+ // ignore fit errors when not visible
1895
+ }
1923
1896
  if (!this.inputDisposable) {
1924
1897
  this.inputDisposable = this.term.onData((data) => {
1925
1898
  if (!this.socket || this.socket.readyState !== WebSocket.OPEN)
@@ -2004,7 +1977,8 @@ export class TerminalManager {
2004
1977
  if (!viewport)
2005
1978
  return;
2006
1979
  const getLineHeight = () => {
2007
- const dims = this.term?._core?._renderService?.dimensions;
1980
+ const core = this.term?._core;
1981
+ const dims = core?._renderService?.dimensions;
2008
1982
  if (dims && Number.isFinite(dims.actualCellHeight) && dims.actualCellHeight > 0) {
2009
1983
  return dims.actualCellHeight;
2010
1984
  }
@@ -3100,7 +3074,8 @@ export class TerminalManager {
3100
3074
  method: "POST",
3101
3075
  body: formData,
3102
3076
  });
3103
- const imagePath = response?.path || response?.abs_path;
3077
+ const p = response;
3078
+ const imagePath = p.path || p.abs_path;
3104
3079
  if (!imagePath) {
3105
3080
  throw new Error("Upload returned no path");
3106
3081
  }