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,504 +0,0 @@
1
- import { api, flash, resolvePath, statusPill, streamEvents } from "./utils.js";
2
- import { registerAutoRefresh } from "./autoRefresh.js";
3
- import { CONSTANTS } from "./constants.js";
4
- function $(id) {
5
- return document.getElementById(id);
6
- }
7
- function setText(el, text) {
8
- if (!el)
9
- return;
10
- el.textContent = text ?? "–";
11
- }
12
- function setLink(el, { href, text, title } = {}) {
13
- if (!el)
14
- return;
15
- if (href) {
16
- el.href = href;
17
- el.target = "_blank";
18
- el.rel = "noopener noreferrer";
19
- el.classList.remove("muted");
20
- el.textContent = text || href;
21
- if (title)
22
- el.title = title;
23
- }
24
- else {
25
- el.removeAttribute("href");
26
- el.removeAttribute("target");
27
- el.removeAttribute("rel");
28
- el.classList.add("muted");
29
- el.textContent = text || "–";
30
- if (title)
31
- el.title = title;
32
- }
33
- }
34
- async function copyToClipboard(text) {
35
- if (!text)
36
- return false;
37
- try {
38
- if (navigator.clipboard?.writeText) {
39
- await navigator.clipboard.writeText(text);
40
- return true;
41
- }
42
- }
43
- catch (err) {
44
- // ignore
45
- }
46
- return false;
47
- }
48
- async function loadGitHubStatus() {
49
- const pill = $("github-status-pill");
50
- const note = $("github-note");
51
- const syncBtn = $("github-sync-pr");
52
- const openFilesBtn = $("github-open-pr-files");
53
- const copyPrBtn = $("github-copy-pr");
54
- try {
55
- const data = await api("/api/github/status");
56
- const gh = (data.gh || {});
57
- const repo = (data.repo || null);
58
- const git = (data.git || {});
59
- const link = (data.link || {});
60
- const issue = (link.issue || null);
61
- const pr = (link.pr || null);
62
- const prLinks = (data.pr_links || null);
63
- if (!gh.available) {
64
- statusPill(pill, "error");
65
- setText(note, "GitHub CLI (gh) not available.");
66
- if (syncBtn)
67
- syncBtn.disabled = true;
68
- }
69
- else if (!gh.authenticated) {
70
- statusPill(pill, "warn");
71
- setText(note, "GitHub CLI not authenticated.");
72
- if (syncBtn)
73
- syncBtn.disabled = true;
74
- }
75
- else {
76
- statusPill(pill, "idle");
77
- setText(note, git.clean ? "Clean working tree." : "Uncommitted changes.");
78
- if (syncBtn)
79
- syncBtn.disabled = false;
80
- }
81
- setLink($("github-repo-link"), {
82
- href: repo?.url,
83
- text: repo?.nameWithOwner || "–",
84
- title: repo?.url || "",
85
- });
86
- setText($("github-branch"), git.branch || "–");
87
- setLink($("github-issue-link"), {
88
- href: issue?.url,
89
- text: issue?.number ? `#${issue.number}` : "–",
90
- title: issue?.title || issue?.url || "",
91
- });
92
- const prUrl = prLinks?.url || pr?.url || null;
93
- setLink($("github-pr-link"), {
94
- href: prUrl || "",
95
- text: pr?.number ? `#${pr.number}` : prUrl ? "PR" : "–",
96
- title: pr?.title || prUrl || "",
97
- });
98
- const hasPr = !!prUrl;
99
- if (openFilesBtn)
100
- openFilesBtn.disabled = !hasPr;
101
- if (copyPrBtn)
102
- copyPrBtn.disabled = !hasPr;
103
- if (openFilesBtn) {
104
- openFilesBtn.onclick = () => {
105
- const files = prLinks?.files || (prUrl ? `${prUrl}/files` : null);
106
- if (!files)
107
- return;
108
- window.open(files, "_blank", "noopener,noreferrer");
109
- };
110
- }
111
- if (copyPrBtn) {
112
- copyPrBtn.onclick = async () => {
113
- if (!prUrl)
114
- return;
115
- const ok = await copyToClipboard(prUrl);
116
- flash(ok ? "Copied PR link" : "Copy failed", ok ? "info" : "error");
117
- };
118
- }
119
- if (syncBtn) {
120
- // Hub install: PR sync always operates on the current worktree/branch.
121
- syncBtn.mode = "current";
122
- }
123
- }
124
- catch (err) {
125
- statusPill(pill, "error");
126
- setText(note, err.message || "Failed to load GitHub status");
127
- if (syncBtn)
128
- syncBtn.disabled = true;
129
- }
130
- }
131
- function prFlowEls() {
132
- return {
133
- statusPill: $("pr-flow-status"),
134
- mode: $("pr-flow-mode"),
135
- ref: $("pr-flow-ref"),
136
- base: $("pr-flow-base"),
137
- until: $("pr-flow-until"),
138
- cycles: $("pr-flow-cycles"),
139
- runs: $("pr-flow-runs"),
140
- timeout: $("pr-flow-timeout"),
141
- draft: $("pr-flow-draft"),
142
- step: $("pr-flow-step"),
143
- cycle: $("pr-flow-cycle"),
144
- review: $("pr-flow-review"),
145
- reviewLink: $("pr-flow-review-link"),
146
- logLink: $("pr-flow-log-link"),
147
- finalLink: $("pr-flow-final-link"),
148
- startBtn: $("pr-flow-start"),
149
- stopBtn: $("pr-flow-stop"),
150
- resumeBtn: $("pr-flow-resume"),
151
- collectBtn: $("pr-flow-collect"),
152
- };
153
- }
154
- function formatMissingPrFlowElements(missing) {
155
- if (missing.length <= 4) {
156
- return missing.join(", ");
157
- }
158
- const extra = missing.length - 4;
159
- return `${missing.slice(0, 4).join(", ")} +${extra} more`;
160
- }
161
- function missingPrFlowElements(els) {
162
- const required = [
163
- ["pr-flow-status", els.statusPill],
164
- ["pr-flow-mode", els.mode],
165
- ["pr-flow-ref", els.ref],
166
- ["pr-flow-base", els.base],
167
- ["pr-flow-until", els.until],
168
- ["pr-flow-cycles", els.cycles],
169
- ["pr-flow-runs", els.runs],
170
- ["pr-flow-timeout", els.timeout],
171
- ["pr-flow-draft", els.draft],
172
- ["pr-flow-step", els.step],
173
- ["pr-flow-cycle", els.cycle],
174
- ["pr-flow-review", els.review],
175
- ["pr-flow-start", els.startBtn],
176
- ["pr-flow-stop", els.stopBtn],
177
- ["pr-flow-resume", els.resumeBtn],
178
- ["pr-flow-collect", els.collectBtn],
179
- ];
180
- return required.filter(([, el]) => !el).map(([id]) => id);
181
- }
182
- function formatReviewSummary(summary) {
183
- if (!summary)
184
- return "–";
185
- const total = summary.total ?? 0;
186
- const major = summary.major ?? 0;
187
- const minor = summary.minor ?? 0;
188
- if (total === 0)
189
- return "No issues";
190
- return `${total} issues (${major} major, ${minor} minor)`;
191
- }
192
- function setArtifactLink(el, kind, hasValue) {
193
- if (!el)
194
- return;
195
- if (!hasValue) {
196
- setLink(el, { href: undefined, text: el.textContent || "–" });
197
- return;
198
- }
199
- setLink(el, {
200
- href: resolvePath(`/api/github/pr_flow/artifact?kind=${kind}`),
201
- text: el.textContent || kind,
202
- title: `Open ${kind.replace("_", " ")}`,
203
- });
204
- }
205
- function setButtonBusy(btn, busy) {
206
- if (!btn)
207
- return;
208
- btn.disabled = busy;
209
- btn.classList.toggle("loading", busy);
210
- }
211
- function setButtonsDisabled(buttons, disabled) {
212
- const previous = buttons.map((btn) => (btn ? btn.disabled : true));
213
- buttons.forEach((btn) => {
214
- if (btn)
215
- btn.disabled = disabled;
216
- });
217
- return previous;
218
- }
219
- function restoreButtonsDisabled(buttons, previous) {
220
- buttons.forEach((btn, idx) => {
221
- if (!btn)
222
- return;
223
- btn.disabled = previous[idx] ?? btn.disabled;
224
- btn.classList.remove("loading");
225
- });
226
- }
227
- function setTemporaryNote(note, message) {
228
- if (!note)
229
- return "";
230
- const previous = note.textContent || "";
231
- note.textContent = message;
232
- return previous;
233
- }
234
- function markPrFlowClick(action) {
235
- const card = $("github-card");
236
- if (card) {
237
- card.dataset.prFlowLastAction = action;
238
- card.dataset.prFlowLastClick = new Date().toISOString();
239
- }
240
- console.debug(`[github] pr flow ${action} click`);
241
- }
242
- function restoreTemporaryNote(note, previous, message) {
243
- if (!note)
244
- return;
245
- if ((note.textContent || "") === message) {
246
- note.textContent = previous;
247
- }
248
- }
249
- async function loadPrFlowStatus() {
250
- const els = prFlowEls();
251
- if (!els.statusPill)
252
- return;
253
- try {
254
- const data = await api("/api/github/pr_flow/status");
255
- const flow = (data.flow || {});
256
- statusPill(els.statusPill, flow.status || "idle");
257
- setText(els.step, flow.step || "–");
258
- setText(els.cycle, flow.cycle ? String(flow.cycle) : "–");
259
- setText(els.review, formatReviewSummary(flow.review_summary));
260
- setArtifactLink(els.reviewLink, "review_bundle", !!flow.review_bundle_path);
261
- setArtifactLink(els.logLink, "workflow_log", !!flow.workflow_log_path);
262
- setArtifactLink(els.finalLink, "final_report", !!flow.final_report_path);
263
- const running = flow.status === "running" || flow.status === "stopping";
264
- if (els.startBtn)
265
- els.startBtn.disabled = running;
266
- if (els.stopBtn)
267
- els.stopBtn.disabled = !running;
268
- if (els.resumeBtn)
269
- els.resumeBtn.disabled = running;
270
- }
271
- catch (_err) {
272
- statusPill(els.statusPill, "error");
273
- setText(els.step, "Error");
274
- }
275
- }
276
- function prFlowPayload() {
277
- const els = prFlowEls();
278
- if (!els.mode || !els.ref)
279
- return null;
280
- const mode = els.mode.value || "issue";
281
- const ref = (els.ref.value || "").trim();
282
- if (!ref)
283
- return null;
284
- const payload = {
285
- mode,
286
- draft: !!els.draft?.checked,
287
- base_branch: (els.base?.value || "").trim() || null,
288
- stop_condition: (els.until?.value || "").trim() || null,
289
- };
290
- const cycles = parseInt(els.cycles?.value || "", 10);
291
- if (!Number.isNaN(cycles) && cycles > 0)
292
- payload.max_cycles = cycles;
293
- const runs = parseInt(els.runs?.value || "", 10);
294
- if (!Number.isNaN(runs) && runs > 0)
295
- payload.max_implementation_runs = runs;
296
- const timeout = parseInt(els.timeout?.value || "", 10);
297
- if (!Number.isNaN(timeout) && timeout >= 0)
298
- payload.max_wallclock_seconds = timeout;
299
- if (mode === "issue") {
300
- payload.issue = ref;
301
- }
302
- else {
303
- payload.pr = ref;
304
- }
305
- return payload;
306
- }
307
- async function startPrFlow() {
308
- const els = prFlowEls();
309
- const note = $("github-note");
310
- markPrFlowClick("start");
311
- setTemporaryNote(note, "PR flow: click received.");
312
- const payload = prFlowPayload();
313
- if (!payload) {
314
- setTemporaryNote(note, "Provide an issue or PR reference.");
315
- flash("Provide an issue or PR reference", "error");
316
- return;
317
- }
318
- const buttons = [els.startBtn, els.stopBtn, els.resumeBtn, els.collectBtn];
319
- const prevDisabled = setButtonsDisabled(buttons, true);
320
- setButtonBusy(els.startBtn, true);
321
- const message = "Starting PR flow...";
322
- const prevNote = setTemporaryNote(note, message);
323
- try {
324
- await api("/api/github/pr_flow/start", { method: "POST", body: payload });
325
- flash("PR flow started");
326
- }
327
- catch (err) {
328
- flash(err.message || "PR flow start failed", "error");
329
- }
330
- finally {
331
- restoreButtonsDisabled(buttons, prevDisabled);
332
- restoreTemporaryNote(note, prevNote, message);
333
- }
334
- await loadPrFlowStatus();
335
- }
336
- async function stopPrFlow() {
337
- const els = prFlowEls();
338
- const note = $("github-note");
339
- markPrFlowClick("stop");
340
- setTemporaryNote(note, "PR flow: click received.");
341
- const buttons = [els.startBtn, els.stopBtn, els.resumeBtn, els.collectBtn];
342
- const prevDisabled = setButtonsDisabled(buttons, true);
343
- setButtonBusy(els.stopBtn, true);
344
- const message = "Stopping PR flow...";
345
- const prevNote = setTemporaryNote(note, message);
346
- try {
347
- await api("/api/github/pr_flow/stop", { method: "POST", body: {} });
348
- flash("PR flow stopping");
349
- }
350
- catch (err) {
351
- flash(err.message || "PR flow stop failed", "error");
352
- }
353
- finally {
354
- restoreButtonsDisabled(buttons, prevDisabled);
355
- restoreTemporaryNote(note, prevNote, message);
356
- }
357
- await loadPrFlowStatus();
358
- }
359
- async function resumePrFlow() {
360
- const els = prFlowEls();
361
- const note = $("github-note");
362
- markPrFlowClick("resume");
363
- setTemporaryNote(note, "PR flow: click received.");
364
- const buttons = [els.startBtn, els.stopBtn, els.resumeBtn, els.collectBtn];
365
- const prevDisabled = setButtonsDisabled(buttons, true);
366
- setButtonBusy(els.resumeBtn, true);
367
- const message = "Resuming PR flow...";
368
- const prevNote = setTemporaryNote(note, message);
369
- try {
370
- await api("/api/github/pr_flow/resume", { method: "POST", body: {} });
371
- flash("PR flow resumed");
372
- }
373
- catch (err) {
374
- flash(err.message || "PR flow resume failed", "error");
375
- }
376
- finally {
377
- restoreButtonsDisabled(buttons, prevDisabled);
378
- restoreTemporaryNote(note, prevNote, message);
379
- }
380
- await loadPrFlowStatus();
381
- }
382
- async function collectPrFlow() {
383
- const els = prFlowEls();
384
- const note = $("github-note");
385
- markPrFlowClick("collect");
386
- setTemporaryNote(note, "PR flow: click received.");
387
- const buttons = [els.startBtn, els.stopBtn, els.resumeBtn, els.collectBtn];
388
- const prevDisabled = setButtonsDisabled(buttons, true);
389
- setButtonBusy(els.collectBtn, true);
390
- const message = "Collecting PR reviews...";
391
- const prevNote = setTemporaryNote(note, message);
392
- try {
393
- await api("/api/github/pr_flow/collect", { method: "POST", body: {} });
394
- flash("Review bundle updated");
395
- }
396
- catch (err) {
397
- flash(err.message || "Review collection failed", "error");
398
- }
399
- finally {
400
- restoreButtonsDisabled(buttons, prevDisabled);
401
- restoreTemporaryNote(note, prevNote, message);
402
- }
403
- await loadPrFlowStatus();
404
- }
405
- async function syncPr() {
406
- const syncBtn = $("github-sync-pr");
407
- const note = $("github-note");
408
- if (!syncBtn)
409
- return;
410
- syncBtn.disabled = true;
411
- syncBtn.classList.add("loading");
412
- const message = "Syncing PR...";
413
- const prevNote = setTemporaryNote(note, message);
414
- try {
415
- const res = await api("/api/github/pr/sync", {
416
- method: "POST",
417
- body: { draft: true },
418
- });
419
- const created = res.created;
420
- flash(created ? "PR created" : "PR synced");
421
- setText(note, "");
422
- await loadGitHubStatus();
423
- }
424
- catch (err) {
425
- flash(err.message || "PR sync failed", "error");
426
- }
427
- finally {
428
- syncBtn.disabled = false;
429
- syncBtn.classList.remove("loading");
430
- restoreTemporaryNote(note, prevNote, message);
431
- }
432
- }
433
- function startPrFlowEventStream() {
434
- const note = $("github-note");
435
- const stop = streamEvents("/api/github/pr_flow/events", {
436
- onMessage: (_data, _event) => {
437
- void loadPrFlowStatus();
438
- },
439
- onError: (err) => {
440
- setTemporaryNote(note, err.message || "PR flow events unavailable");
441
- if (stop)
442
- stop();
443
- },
444
- });
445
- }
446
- export function initGitHub() {
447
- const card = $("github-card");
448
- if (!card)
449
- return;
450
- card.dataset.githubInitialized = "true";
451
- console.debug("[github] init");
452
- const syncBtn = $("github-sync-pr");
453
- if (syncBtn)
454
- syncBtn.addEventListener("click", syncPr);
455
- const els = prFlowEls();
456
- const prFlowContainer = card.querySelector(".github-flow");
457
- const missingPrFlow = missingPrFlowElements(els);
458
- const prFlowReady = missingPrFlow.length === 0;
459
- if (!prFlowReady) {
460
- if (prFlowContainer) {
461
- prFlowContainer.dataset.prFlowInitialized = "0";
462
- }
463
- if (!card.dataset.prFlowInitError) {
464
- const summary = formatMissingPrFlowElements(missingPrFlow);
465
- const message = `PR Flow UI not initialized (missing ${summary}). Static assets may be out of date; rebuild frontend bundle.`;
466
- card.dataset.prFlowInitError = summary;
467
- flash(message, "error");
468
- console.warn(`[github] ${message}`);
469
- }
470
- }
471
- else {
472
- if (prFlowContainer) {
473
- prFlowContainer.dataset.prFlowInitialized = "1";
474
- }
475
- if (els.startBtn)
476
- els.startBtn.addEventListener("click", startPrFlow);
477
- if (els.stopBtn)
478
- els.stopBtn.addEventListener("click", stopPrFlow);
479
- if (els.resumeBtn)
480
- els.resumeBtn.addEventListener("click", resumePrFlow);
481
- if (els.collectBtn)
482
- els.collectBtn.addEventListener("click", collectPrFlow);
483
- }
484
- // Initial load + auto-refresh while dashboard is active.
485
- loadGitHubStatus();
486
- registerAutoRefresh("github-status", {
487
- callback: loadGitHubStatus,
488
- tabId: null, // global: keep PR link available while browsing other tabs (mobile-friendly)
489
- interval: CONSTANTS.UI?.AUTO_REFRESH_INTERVAL || 15000,
490
- refreshOnActivation: true,
491
- immediate: false,
492
- });
493
- if (prFlowReady) {
494
- loadPrFlowStatus();
495
- registerAutoRefresh("pr-flow-status", {
496
- callback: loadPrFlowStatus,
497
- tabId: null,
498
- interval: CONSTANTS.UI?.AUTO_REFRESH_INTERVAL || 15000,
499
- refreshOnActivation: true,
500
- immediate: false,
501
- });
502
- startPrFlowEventStream();
503
- }
504
- }