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,3 +1,4 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
1
2
  import { isMobileViewport, setMobileChromeHidden, setMobileComposeFixed, } from "./utils.js";
2
3
  import { subscribe } from "./bus.js";
3
4
  import { getTerminalManager } from "./terminal.js";
@@ -100,7 +101,7 @@ function updateMobileControlsOffset() {
100
101
  document.documentElement.style.setProperty("--compose-total-height", `${totalHeight}px`);
101
102
  }
102
103
  function updateDocComposeOffset() {
103
- const composePanel = document.querySelector("#docs .doc-chat-panel");
104
+ const composePanel = document.querySelector("#workspace .doc-chat-panel, #workspace .ticket-chat-panel");
104
105
  if (!composePanel || !isVisible(composePanel))
105
106
  return;
106
107
  const composeHeight = composePanel.offsetHeight || 0;
@@ -0,0 +1,17 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
2
+ export function preserveScroll(el, render, opts) {
3
+ if (!el) {
4
+ render();
5
+ return;
6
+ }
7
+ const top = el.scrollTop;
8
+ render();
9
+ const restore = () => {
10
+ el.scrollTop = top;
11
+ };
12
+ if (opts?.restoreOnNextFrame && typeof requestAnimationFrame === "function") {
13
+ requestAnimationFrame(restore);
14
+ return;
15
+ }
16
+ restore();
17
+ }
@@ -1,190 +1,13 @@
1
- import { api, confirmModal, flash, resolvePath } from "./utils.js";
2
- let modelsCache = [];
3
- let currentSettings = null;
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
2
+ import { api, confirmModal, flash, resolvePath, openModal } from "./utils.js";
4
3
  const ui = {
5
4
  settingsBtn: document.getElementById("repo-settings"),
6
- modelSelect: document.getElementById("autorunner-model-select"),
7
- effortSelect: document.getElementById("autorunner-effort-select"),
8
- approvalSelect: document.getElementById("autorunner-approval-select"),
9
- sandboxSelect: document.getElementById("autorunner-sandbox-select"),
10
- maxRunsInput: document.getElementById("autorunner-max-runs-input"),
11
- networkToggle: document.getElementById("autorunner-network-toggle"),
12
- networkRow: document.getElementById("autorunner-network-row"),
13
- saveBtn: document.getElementById("autorunner-settings-save"),
14
- reloadBtn: document.getElementById("autorunner-settings-reload"),
15
- warning: document.getElementById("autorunner-settings-warning"),
16
5
  threadList: document.getElementById("thread-tools-list"),
17
6
  threadNew: document.getElementById("thread-new-autorunner"),
18
7
  threadArchive: document.getElementById("thread-archive-autorunner"),
19
8
  threadResetAll: document.getElementById("thread-reset-all"),
20
9
  threadDownload: document.getElementById("thread-backup-download"),
21
10
  };
22
- const DEFAULT_EFFORTS = ["low", "medium", "high"];
23
- function getModelId(model) {
24
- if (!model || typeof model !== "object")
25
- return null;
26
- const modelObj = model;
27
- const keys = ["id", "model", "name", "model_id", "modelId"];
28
- for (const key of keys) {
29
- const value = modelObj[key];
30
- if (typeof value === "string" && value.trim()) {
31
- return value.trim();
32
- }
33
- }
34
- return null;
35
- }
36
- function getModelEfforts(model) {
37
- if (!model || typeof model !== "object")
38
- return null;
39
- const modelObj = model;
40
- const keys = [
41
- "supported_reasoning_efforts",
42
- "supportedReasoningEfforts",
43
- "reasoning_efforts",
44
- "reasoningEfforts",
45
- "supported_efforts",
46
- "supportedEfforts",
47
- "efforts",
48
- ];
49
- for (const key of keys) {
50
- const value = modelObj[key];
51
- if (Array.isArray(value) && value.length) {
52
- return value.map((entry) => String(entry));
53
- }
54
- }
55
- return null;
56
- }
57
- function normalizeModels(raw) {
58
- if (Array.isArray(raw))
59
- return raw;
60
- if (raw && typeof raw === "object") {
61
- const rawObj = raw;
62
- if (Array.isArray(rawObj.models))
63
- return rawObj.models;
64
- if (Array.isArray(rawObj.data))
65
- return rawObj.data;
66
- if (Array.isArray(rawObj.items))
67
- return rawObj.items;
68
- if (Array.isArray(rawObj.results))
69
- return rawObj.results;
70
- }
71
- return [];
72
- }
73
- function setOptions(select, options, selected, placeholder) {
74
- if (!select)
75
- return;
76
- select.innerHTML = "";
77
- const empty = document.createElement("option");
78
- empty.value = "";
79
- empty.textContent = placeholder;
80
- select.appendChild(empty);
81
- options.forEach((opt) => {
82
- const option = document.createElement("option");
83
- option.value = opt.value;
84
- option.textContent = opt.label;
85
- select.appendChild(option);
86
- });
87
- if (selected) {
88
- const exists = options.some((opt) => opt.value === selected);
89
- if (!exists) {
90
- const custom = document.createElement("option");
91
- custom.value = selected;
92
- custom.textContent = `${selected} (custom)`;
93
- select.appendChild(custom);
94
- }
95
- select.value = selected;
96
- }
97
- else {
98
- select.value = "";
99
- }
100
- }
101
- function updateNetworkVisibility() {
102
- if (!ui.networkRow || !ui.sandboxSelect)
103
- return;
104
- const show = ui.sandboxSelect.value === "workspaceWrite";
105
- ui.networkRow.classList.toggle("hidden", !show);
106
- }
107
- async function loadModels() {
108
- try {
109
- const data = await api("/api/app-server/models");
110
- modelsCache = normalizeModels(data);
111
- }
112
- catch (err) {
113
- modelsCache = [];
114
- const error = err;
115
- flash(error.message || "Failed to load models", "error");
116
- }
117
- }
118
- async function loadSessionSettings() {
119
- const data = await api("/api/session/settings");
120
- currentSettings = data;
121
- return data;
122
- }
123
- function renderSettings(settings) {
124
- if (!settings)
125
- return;
126
- const modelOptions = modelsCache
127
- .map((model) => {
128
- const id = getModelId(model);
129
- return id ? { value: id, label: id } : null;
130
- })
131
- .filter((opt) => opt !== null);
132
- setOptions(ui.modelSelect, modelOptions, settings.autorunner_model_override, "Default model");
133
- const selectedModelId = ui.modelSelect?.value || settings.autorunner_model_override;
134
- const selectedModel = modelsCache.find((model) => getModelId(model) === selectedModelId) || null;
135
- const efforts = getModelEfforts(selectedModel) || [...DEFAULT_EFFORTS];
136
- const effortOptions = efforts.map((effort) => ({
137
- value: effort,
138
- label: effort,
139
- }));
140
- setOptions(ui.effortSelect, effortOptions, settings.autorunner_effort_override, "Default effort");
141
- setOptions(ui.approvalSelect, [
142
- { value: "never", label: "Never" },
143
- { value: "unlessTrusted", label: "Unless trusted" },
144
- ], settings.autorunner_approval_policy, "Default approval");
145
- setOptions(ui.sandboxSelect, [
146
- { value: "dangerFullAccess", label: "Full access" },
147
- { value: "workspaceWrite", label: "Workspace write" },
148
- ], settings.autorunner_sandbox_mode, "Default sandbox");
149
- if (ui.networkToggle) {
150
- ui.networkToggle.checked = Boolean(settings.autorunner_workspace_write_network);
151
- }
152
- if (ui.maxRunsInput) {
153
- const maxRuns = settings.runner_stop_after_runs;
154
- ui.maxRunsInput.value = maxRuns ? String(maxRuns) : "";
155
- }
156
- updateNetworkVisibility();
157
- }
158
- async function saveSettings() {
159
- if (!ui.saveBtn)
160
- return;
161
- ui.saveBtn.disabled = true;
162
- ui.saveBtn.classList.add("loading");
163
- try {
164
- const payload = {
165
- autorunner_model_override: ui.modelSelect?.value || null,
166
- autorunner_effort_override: ui.effortSelect?.value || null,
167
- autorunner_approval_policy: ui.approvalSelect?.value || null,
168
- autorunner_sandbox_mode: ui.sandboxSelect?.value || null,
169
- autorunner_workspace_write_network: Boolean(ui.networkToggle?.checked),
170
- runner_stop_after_runs: ui.maxRunsInput?.value ? parseInt(ui.maxRunsInput.value, 10) : null,
171
- };
172
- const data = await api("/api/session/settings", {
173
- method: "POST",
174
- body: payload,
175
- });
176
- currentSettings = data;
177
- flash("Autorunner settings saved", "success");
178
- }
179
- catch (err) {
180
- const error = err;
181
- flash(error.message || "Failed to save settings", "error");
182
- }
183
- finally {
184
- ui.saveBtn.disabled = false;
185
- ui.saveBtn.classList.remove("loading");
186
- }
187
- }
188
11
  function renderThreadTools(data) {
189
12
  if (!ui.threadList)
190
13
  return;
@@ -197,17 +20,25 @@ function renderThreadTools(data) {
197
20
  if (data.autorunner !== undefined) {
198
21
  entries.push({ label: "Autorunner", value: data.autorunner || "—" });
199
22
  }
200
- if (data.spec_ingest !== undefined) {
201
- entries.push({ label: "Spec ingest", value: data.spec_ingest || "—" });
23
+ if (data.file_chat !== undefined) {
24
+ entries.push({ label: "File chat", value: data.file_chat || "—" });
202
25
  }
203
- if (data.doc_chat && typeof data.doc_chat === "object") {
204
- Object.keys(data.doc_chat).forEach((key) => {
205
- entries.push({
206
- label: `Doc chat (${key})`,
207
- value: data.doc_chat[key] || "—",
208
- });
26
+ if (data.file_chat_opencode !== undefined) {
27
+ entries.push({
28
+ label: "File chat (opencode)",
29
+ value: data.file_chat_opencode || "—",
209
30
  });
210
31
  }
32
+ // Render any additional string/number keys to avoid hiding future entries.
33
+ Object.keys(data).forEach((key) => {
34
+ if (["autorunner", "file_chat", "file_chat_opencode", "corruption"].includes(key)) {
35
+ return;
36
+ }
37
+ const value = data[key];
38
+ if (typeof value === "string" || typeof value === "number") {
39
+ entries.push({ label: key, value: value || "—" });
40
+ }
41
+ });
211
42
  if (!entries.length) {
212
43
  ui.threadList.textContent = "No threads recorded.";
213
44
  return;
@@ -239,39 +70,12 @@ async function loadThreadTools() {
239
70
  }
240
71
  }
241
72
  async function refreshSettings() {
242
- await loadModels();
243
- const settings = await loadSessionSettings();
244
- renderSettings(settings);
245
73
  await loadThreadTools();
246
74
  }
247
75
  export function initRepoSettingsPanel() {
248
- if (ui.settingsBtn) {
249
- ui.settingsBtn.addEventListener("click", () => {
250
- refreshSettings();
251
- });
252
- }
253
- if (ui.modelSelect) {
254
- ui.modelSelect.addEventListener("change", () => {
255
- if (!currentSettings)
256
- return;
257
- const currentEffort = ui.effortSelect?.value || null;
258
- const updated = {
259
- ...currentSettings,
260
- autorunner_model_override: ui.modelSelect.value || null,
261
- autorunner_effort_override: currentEffort || currentSettings.autorunner_effort_override,
262
- };
263
- renderSettings(updated);
264
- });
265
- }
266
- if (ui.sandboxSelect) {
267
- ui.sandboxSelect.addEventListener("change", updateNetworkVisibility);
268
- }
269
- if (ui.saveBtn) {
270
- ui.saveBtn.addEventListener("click", () => saveSettings());
271
- }
272
- if (ui.reloadBtn) {
273
- ui.reloadBtn.addEventListener("click", () => refreshSettings());
274
- }
76
+ window.__CAR_SETTINGS = { loadThreadTools, refreshSettings };
77
+ // Initialize the modal interaction
78
+ initRepoSettingsModal();
275
79
  if (ui.threadNew) {
276
80
  ui.threadNew.addEventListener("click", async () => {
277
81
  try {
@@ -338,4 +142,132 @@ export function initRepoSettingsPanel() {
338
142
  window.location.href = resolvePath("/api/app-server/threads/backup");
339
143
  });
340
144
  }
145
+ // Clear cached logs since log loading is no longer available
146
+ try {
147
+ localStorage.removeItem("logs:tail");
148
+ }
149
+ catch (_err) {
150
+ // ignore
151
+ }
152
+ }
153
+ const UPDATE_TARGET_LABELS = {
154
+ both: "web + Telegram",
155
+ web: "web only",
156
+ telegram: "Telegram only",
157
+ };
158
+ function normalizeUpdateTarget(value) {
159
+ if (!value)
160
+ return "both";
161
+ if (value === "both" || value === "web" || value === "telegram")
162
+ return value;
163
+ return "both";
164
+ }
165
+ function getUpdateTarget(selectId) {
166
+ const select = selectId ? document.getElementById(selectId) : null;
167
+ return normalizeUpdateTarget(select ? select.value : "both");
168
+ }
169
+ function describeUpdateTarget(target) {
170
+ return UPDATE_TARGET_LABELS[target] || UPDATE_TARGET_LABELS.both;
171
+ }
172
+ async function handleSystemUpdate(btnId, targetSelectId) {
173
+ const btn = document.getElementById(btnId);
174
+ if (!btn)
175
+ return;
176
+ const originalText = btn.textContent;
177
+ btn.disabled = true;
178
+ btn.textContent = "Checking...";
179
+ const updateTarget = getUpdateTarget(targetSelectId);
180
+ const targetLabel = describeUpdateTarget(updateTarget);
181
+ let check;
182
+ try {
183
+ check = await api("/system/update/check");
184
+ }
185
+ catch (err) {
186
+ check = { update_available: true, message: err.message || "Unable to check for updates." };
187
+ }
188
+ if (!check?.update_available) {
189
+ flash(check?.message || "No update available.", "info");
190
+ btn.disabled = false;
191
+ btn.textContent = originalText;
192
+ return;
193
+ }
194
+ const restartNotice = updateTarget === "telegram"
195
+ ? "The Telegram bot will restart."
196
+ : "The service will restart.";
197
+ const confirmed = await confirmModal(`${check?.message || "Update available."} Update Codex Autorunner (${targetLabel})? ${restartNotice}`);
198
+ if (!confirmed) {
199
+ btn.disabled = false;
200
+ btn.textContent = originalText;
201
+ return;
202
+ }
203
+ btn.textContent = "Updating...";
204
+ try {
205
+ const res = await api("/system/update", {
206
+ method: "POST",
207
+ body: { target: updateTarget },
208
+ });
209
+ flash(res.message || `Update started (${targetLabel}).`, "success");
210
+ if (updateTarget === "telegram") {
211
+ btn.disabled = false;
212
+ btn.textContent = originalText;
213
+ return;
214
+ }
215
+ document.body.style.pointerEvents = "none";
216
+ setTimeout(() => {
217
+ const url = new URL(window.location.href);
218
+ url.searchParams.set("v", String(Date.now()));
219
+ window.location.replace(url.toString());
220
+ }, 8000);
221
+ }
222
+ catch (err) {
223
+ flash(err.message || "Update failed", "error");
224
+ btn.disabled = false;
225
+ btn.textContent = originalText;
226
+ }
227
+ }
228
+ let repoSettingsCloseModal = null;
229
+ function hideRepoSettingsModal() {
230
+ if (repoSettingsCloseModal) {
231
+ const close = repoSettingsCloseModal;
232
+ repoSettingsCloseModal = null;
233
+ close();
234
+ }
235
+ }
236
+ export function openRepoSettings(triggerEl) {
237
+ const modal = document.getElementById("repo-settings-modal");
238
+ const closeBtn = document.getElementById("repo-settings-close");
239
+ const updateBtn = document.getElementById("repo-update-btn");
240
+ if (!modal)
241
+ return;
242
+ hideRepoSettingsModal();
243
+ repoSettingsCloseModal = openModal(modal, {
244
+ initialFocus: closeBtn || updateBtn || modal,
245
+ returnFocusTo: triggerEl || null,
246
+ onRequestClose: hideRepoSettingsModal,
247
+ });
248
+ // Trigger settings refresh when modal opens
249
+ const { refreshSettings } = window.__CAR_SETTINGS || {};
250
+ if (typeof refreshSettings === "function") {
251
+ refreshSettings();
252
+ }
253
+ }
254
+ function initRepoSettingsModal() {
255
+ const settingsBtn = document.getElementById("repo-settings");
256
+ const closeBtn = document.getElementById("repo-settings-close");
257
+ const updateBtn = document.getElementById("repo-update-btn");
258
+ const updateTarget = document.getElementById("repo-update-target");
259
+ // If the gear button exists in HTML, wire it up (backwards compatibility)
260
+ if (settingsBtn) {
261
+ settingsBtn.addEventListener("click", () => {
262
+ openRepoSettings(settingsBtn);
263
+ });
264
+ }
265
+ if (closeBtn) {
266
+ closeBtn.addEventListener("click", () => {
267
+ hideRepoSettingsModal();
268
+ });
269
+ }
270
+ if (updateBtn) {
271
+ updateBtn.addEventListener("click", () => handleSystemUpdate("repo-update-btn", updateTarget ? updateTarget.id : null));
272
+ }
341
273
  }
@@ -0,0 +1,52 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
2
+ /**
3
+ * Create a signature-aware refresh helper that only calls render when data changes.
4
+ *
5
+ * Usage:
6
+ * const smartRefresh = createSmartRefresh({
7
+ * getSignature: (payload) => payload.items.map((i) => i.id).join("|"),
8
+ * render: (payload) => renderList(payload.items),
9
+ * });
10
+ *
11
+ * await smartRefresh.refresh(loadItems, { reason: "background" });
12
+ */
13
+ export function createSmartRefresh(options) {
14
+ let lastSignature = options.initialSignature ?? null;
15
+ const refresh = async (load, request = {}) => {
16
+ const payload = await load();
17
+ const nextSignature = options.getSignature(payload);
18
+ const previousSignature = lastSignature;
19
+ const isInitial = previousSignature === null || request.reason === "initial";
20
+ const isForced = Boolean(request.force);
21
+ const updated = isForced || isInitial || nextSignature !== previousSignature;
22
+ const reason = request.reason ?? (isInitial ? "initial" : "background");
23
+ const ctx = {
24
+ isInitial,
25
+ isForced,
26
+ previousSignature,
27
+ nextSignature,
28
+ updated,
29
+ reason,
30
+ };
31
+ if (updated) {
32
+ lastSignature = nextSignature;
33
+ await options.render(payload, ctx);
34
+ }
35
+ else if (options.onSkip) {
36
+ await options.onSkip(payload, ctx);
37
+ }
38
+ return {
39
+ updated,
40
+ signature: nextSignature,
41
+ previousSignature,
42
+ reason,
43
+ };
44
+ };
45
+ return {
46
+ refresh,
47
+ reset: () => {
48
+ lastSignature = null;
49
+ },
50
+ getSignature: () => lastSignature,
51
+ };
52
+ }