codex-autorunner 1.1.0__py3-none-any.whl → 1.2.1__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 (134) hide show
  1. codex_autorunner/agents/opencode/client.py +113 -4
  2. codex_autorunner/agents/opencode/supervisor.py +4 -0
  3. codex_autorunner/agents/registry.py +17 -7
  4. codex_autorunner/bootstrap.py +219 -1
  5. codex_autorunner/core/__init__.py +17 -1
  6. codex_autorunner/core/about_car.py +124 -11
  7. codex_autorunner/core/app_server_threads.py +6 -0
  8. codex_autorunner/core/config.py +238 -3
  9. codex_autorunner/core/context_awareness.py +39 -0
  10. codex_autorunner/core/docs.py +0 -122
  11. codex_autorunner/core/filebox.py +265 -0
  12. codex_autorunner/core/flows/controller.py +71 -1
  13. codex_autorunner/core/flows/reconciler.py +4 -1
  14. codex_autorunner/core/flows/runtime.py +22 -0
  15. codex_autorunner/core/flows/store.py +61 -9
  16. codex_autorunner/core/flows/transition.py +23 -16
  17. codex_autorunner/core/flows/ux_helpers.py +18 -3
  18. codex_autorunner/core/flows/worker_process.py +32 -6
  19. codex_autorunner/core/hub.py +198 -41
  20. codex_autorunner/core/lifecycle_events.py +253 -0
  21. codex_autorunner/core/path_utils.py +2 -1
  22. codex_autorunner/core/pma_audit.py +224 -0
  23. codex_autorunner/core/pma_context.py +683 -0
  24. codex_autorunner/core/pma_dispatch_interceptor.py +284 -0
  25. codex_autorunner/core/pma_lifecycle.py +527 -0
  26. codex_autorunner/core/pma_queue.py +367 -0
  27. codex_autorunner/core/pma_safety.py +221 -0
  28. codex_autorunner/core/pma_state.py +115 -0
  29. codex_autorunner/core/ports/agent_backend.py +2 -5
  30. codex_autorunner/core/ports/run_event.py +1 -4
  31. codex_autorunner/core/prompt.py +0 -80
  32. codex_autorunner/core/prompts.py +56 -172
  33. codex_autorunner/core/redaction.py +0 -4
  34. codex_autorunner/core/review_context.py +11 -9
  35. codex_autorunner/core/runner_controller.py +35 -33
  36. codex_autorunner/core/runner_state.py +147 -0
  37. codex_autorunner/core/runtime.py +829 -0
  38. codex_autorunner/core/sqlite_utils.py +13 -4
  39. codex_autorunner/core/state.py +7 -10
  40. codex_autorunner/core/state_roots.py +5 -0
  41. codex_autorunner/core/templates/__init__.py +39 -0
  42. codex_autorunner/core/templates/git_mirror.py +234 -0
  43. codex_autorunner/core/templates/provenance.py +56 -0
  44. codex_autorunner/core/templates/scan_cache.py +120 -0
  45. codex_autorunner/core/ticket_linter_cli.py +17 -0
  46. codex_autorunner/core/ticket_manager_cli.py +154 -92
  47. codex_autorunner/core/time_utils.py +11 -0
  48. codex_autorunner/core/types.py +18 -0
  49. codex_autorunner/core/utils.py +34 -6
  50. codex_autorunner/flows/review/service.py +23 -25
  51. codex_autorunner/flows/ticket_flow/definition.py +43 -1
  52. codex_autorunner/integrations/agents/__init__.py +2 -0
  53. codex_autorunner/integrations/agents/backend_orchestrator.py +18 -0
  54. codex_autorunner/integrations/agents/codex_backend.py +19 -8
  55. codex_autorunner/integrations/agents/runner.py +3 -8
  56. codex_autorunner/integrations/agents/wiring.py +8 -0
  57. codex_autorunner/integrations/telegram/adapter.py +1 -1
  58. codex_autorunner/integrations/telegram/config.py +1 -1
  59. codex_autorunner/integrations/telegram/doctor.py +228 -6
  60. codex_autorunner/integrations/telegram/handlers/commands/execution.py +236 -74
  61. codex_autorunner/integrations/telegram/handlers/commands/files.py +314 -75
  62. codex_autorunner/integrations/telegram/handlers/commands/flows.py +346 -58
  63. codex_autorunner/integrations/telegram/handlers/commands/workspace.py +498 -37
  64. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +202 -45
  65. codex_autorunner/integrations/telegram/handlers/commands_spec.py +18 -7
  66. codex_autorunner/integrations/telegram/handlers/messages.py +34 -3
  67. codex_autorunner/integrations/telegram/helpers.py +1 -3
  68. codex_autorunner/integrations/telegram/runtime.py +9 -4
  69. codex_autorunner/integrations/telegram/service.py +30 -0
  70. codex_autorunner/integrations/telegram/state.py +38 -0
  71. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +10 -4
  72. codex_autorunner/integrations/telegram/transport.py +10 -3
  73. codex_autorunner/integrations/templates/__init__.py +27 -0
  74. codex_autorunner/integrations/templates/scan_agent.py +312 -0
  75. codex_autorunner/server.py +2 -2
  76. codex_autorunner/static/agentControls.js +21 -5
  77. codex_autorunner/static/app.js +115 -11
  78. codex_autorunner/static/archive.js +274 -81
  79. codex_autorunner/static/archiveApi.js +21 -0
  80. codex_autorunner/static/chatUploads.js +137 -0
  81. codex_autorunner/static/constants.js +1 -1
  82. codex_autorunner/static/docChatCore.js +185 -13
  83. codex_autorunner/static/fileChat.js +68 -40
  84. codex_autorunner/static/fileboxUi.js +159 -0
  85. codex_autorunner/static/hub.js +46 -81
  86. codex_autorunner/static/index.html +303 -24
  87. codex_autorunner/static/messages.js +82 -4
  88. codex_autorunner/static/notifications.js +288 -0
  89. codex_autorunner/static/pma.js +1167 -0
  90. codex_autorunner/static/settings.js +3 -0
  91. codex_autorunner/static/streamUtils.js +57 -0
  92. codex_autorunner/static/styles.css +9141 -6742
  93. codex_autorunner/static/templateReposSettings.js +225 -0
  94. codex_autorunner/static/terminalManager.js +22 -3
  95. codex_autorunner/static/ticketChatActions.js +165 -3
  96. codex_autorunner/static/ticketChatStream.js +17 -119
  97. codex_autorunner/static/ticketEditor.js +41 -13
  98. codex_autorunner/static/ticketTemplates.js +798 -0
  99. codex_autorunner/static/tickets.js +69 -19
  100. codex_autorunner/static/turnEvents.js +27 -0
  101. codex_autorunner/static/turnResume.js +33 -0
  102. codex_autorunner/static/utils.js +28 -0
  103. codex_autorunner/static/workspace.js +258 -44
  104. codex_autorunner/static/workspaceFileBrowser.js +6 -4
  105. codex_autorunner/surfaces/cli/cli.py +1465 -155
  106. codex_autorunner/surfaces/cli/pma_cli.py +817 -0
  107. codex_autorunner/surfaces/web/app.py +253 -49
  108. codex_autorunner/surfaces/web/routes/__init__.py +4 -0
  109. codex_autorunner/surfaces/web/routes/analytics.py +29 -22
  110. codex_autorunner/surfaces/web/routes/archive.py +197 -0
  111. codex_autorunner/surfaces/web/routes/file_chat.py +297 -36
  112. codex_autorunner/surfaces/web/routes/filebox.py +227 -0
  113. codex_autorunner/surfaces/web/routes/flows.py +219 -29
  114. codex_autorunner/surfaces/web/routes/messages.py +70 -39
  115. codex_autorunner/surfaces/web/routes/pma.py +1652 -0
  116. codex_autorunner/surfaces/web/routes/repos.py +1 -1
  117. codex_autorunner/surfaces/web/routes/shared.py +0 -3
  118. codex_autorunner/surfaces/web/routes/templates.py +634 -0
  119. codex_autorunner/surfaces/web/runner_manager.py +2 -2
  120. codex_autorunner/surfaces/web/schemas.py +81 -18
  121. codex_autorunner/tickets/agent_pool.py +27 -0
  122. codex_autorunner/tickets/files.py +33 -16
  123. codex_autorunner/tickets/lint.py +50 -0
  124. codex_autorunner/tickets/models.py +3 -0
  125. codex_autorunner/tickets/outbox.py +41 -5
  126. codex_autorunner/tickets/runner.py +350 -69
  127. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/METADATA +15 -19
  128. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/RECORD +132 -101
  129. codex_autorunner/core/adapter_utils.py +0 -21
  130. codex_autorunner/core/engine.py +0 -3302
  131. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/WHEEL +0 -0
  132. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/entry_points.txt +0 -0
  133. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/licenses/LICENSE +0 -0
  134. {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,288 @@
1
+ // GENERATED FILE - do not edit directly. Source: static_src/
2
+ import { api, escapeHtml, openModal, resolvePath } from "./utils.js";
3
+ import { registerAutoRefresh } from "./autoRefresh.js";
4
+ let notificationsInitialized = false;
5
+ let notificationItems = [];
6
+ let activeRoot = null;
7
+ let closeModalFn = null;
8
+ let documentListenerInstalled = false;
9
+ let modalElements = null;
10
+ let isRefreshing = false;
11
+ const DROPDOWN_MARGIN = 8;
12
+ const DROPDOWN_OFFSET = 6;
13
+ const NOTIFICATIONS_REFRESH_ID = "notifications";
14
+ const NOTIFICATIONS_REFRESH_MS = 15000;
15
+ function getModalElements() {
16
+ if (modalElements)
17
+ return modalElements;
18
+ const overlay = document.getElementById("notifications-modal");
19
+ const body = document.getElementById("notifications-modal-body");
20
+ const closeBtn = document.getElementById("notifications-modal-close");
21
+ if (!overlay || !body || !closeBtn)
22
+ return null;
23
+ modalElements = { overlay, body, closeBtn };
24
+ return modalElements;
25
+ }
26
+ function getRootElements(root) {
27
+ const trigger = root.querySelector("[data-notifications-trigger]");
28
+ const badge = root.querySelector("[data-notifications-badge]");
29
+ const dropdown = root.querySelector("[data-notifications-dropdown]");
30
+ if (!trigger || !badge || !dropdown)
31
+ return null;
32
+ return { root, trigger, badge, dropdown };
33
+ }
34
+ function setBadgeCount(count) {
35
+ const roots = document.querySelectorAll("[data-notifications-root]");
36
+ roots.forEach((root) => {
37
+ const elements = getRootElements(root);
38
+ if (!elements)
39
+ return;
40
+ elements.badge.textContent = count > 0 ? String(count) : "";
41
+ elements.badge.classList.toggle("hidden", count <= 0);
42
+ elements.trigger.setAttribute("aria-label", count > 0 ? `Notifications (${count})` : "Notifications");
43
+ });
44
+ }
45
+ function normalizeItem(item) {
46
+ const repoId = String(item.repo_id || "");
47
+ const repoDisplay = item.repo_display_name || repoId;
48
+ const mode = item.dispatch?.mode || "";
49
+ const title = (item.dispatch?.title || "").trim();
50
+ const fallbackTitle = title || mode || "Dispatch";
51
+ const body = item.dispatch?.body || "";
52
+ const isHandoff = Boolean(item.dispatch?.is_handoff) || mode === "pause";
53
+ const runId = String(item.run_id || "");
54
+ const openUrl = item.open_url || `/repos/${repoId}/?tab=inbox&run_id=${runId}`;
55
+ return {
56
+ repoId,
57
+ repoDisplay,
58
+ runId,
59
+ status: item.status || "paused",
60
+ seq: item.seq,
61
+ title: fallbackTitle,
62
+ mode,
63
+ body,
64
+ isHandoff,
65
+ openUrl,
66
+ };
67
+ }
68
+ function renderDropdown(root) {
69
+ if (!root)
70
+ return;
71
+ if (!notificationItems.length) {
72
+ root.dropdown.innerHTML = '<div class="notifications-empty muted small">No pending dispatches</div>';
73
+ return;
74
+ }
75
+ const html = notificationItems
76
+ .map((item, index) => {
77
+ const pill = item.isHandoff ? "handoff" : "paused";
78
+ return `
79
+ <button class="notifications-item" type="button" data-index="${index}">
80
+ <span class="notifications-item-repo">${escapeHtml(item.repoDisplay)}</span>
81
+ <span class="notifications-item-title">${escapeHtml(item.title)}</span>
82
+ <span class="pill pill-small pill-warn notifications-item-pill">${escapeHtml(pill)}</span>
83
+ </button>
84
+ `;
85
+ })
86
+ .join("");
87
+ root.dropdown.innerHTML = html;
88
+ }
89
+ function renderDropdownError(root) {
90
+ if (!root)
91
+ return;
92
+ root.dropdown.innerHTML = '<div class="notifications-empty muted small">Failed to load dispatches</div>';
93
+ }
94
+ function closeDropdown() {
95
+ if (!activeRoot)
96
+ return;
97
+ activeRoot.dropdown.classList.add("hidden");
98
+ activeRoot.dropdown.style.position = "";
99
+ activeRoot.dropdown.style.left = "";
100
+ activeRoot.dropdown.style.right = "";
101
+ activeRoot.dropdown.style.top = "";
102
+ activeRoot.dropdown.style.visibility = "";
103
+ activeRoot.trigger.setAttribute("aria-expanded", "false");
104
+ activeRoot = null;
105
+ removeDocumentListener();
106
+ }
107
+ function positionDropdown(root) {
108
+ const { trigger, dropdown } = root;
109
+ const triggerRect = trigger.getBoundingClientRect();
110
+ dropdown.style.position = "fixed";
111
+ dropdown.style.left = "0";
112
+ dropdown.style.right = "auto";
113
+ dropdown.style.top = "0";
114
+ dropdown.style.visibility = "hidden";
115
+ const dropdownRect = dropdown.getBoundingClientRect();
116
+ const width = dropdownRect.width || 240;
117
+ const height = dropdownRect.height || 0;
118
+ const viewportWidth = window.innerWidth;
119
+ const viewportHeight = window.innerHeight;
120
+ let left = triggerRect.right - width;
121
+ left = Math.min(Math.max(left, DROPDOWN_MARGIN), viewportWidth - width - DROPDOWN_MARGIN);
122
+ const preferredTop = triggerRect.bottom + DROPDOWN_OFFSET;
123
+ const fallbackTop = triggerRect.top - DROPDOWN_OFFSET - height;
124
+ let top = preferredTop;
125
+ if (preferredTop + height > viewportHeight - DROPDOWN_MARGIN) {
126
+ top = Math.max(DROPDOWN_MARGIN, fallbackTop);
127
+ }
128
+ dropdown.style.left = `${Math.max(DROPDOWN_MARGIN, left)}px`;
129
+ dropdown.style.top = `${Math.max(DROPDOWN_MARGIN, top)}px`;
130
+ dropdown.style.visibility = "";
131
+ }
132
+ function openDropdown(root) {
133
+ if (activeRoot && activeRoot !== root) {
134
+ activeRoot.dropdown.classList.add("hidden");
135
+ activeRoot.trigger.setAttribute("aria-expanded", "false");
136
+ }
137
+ activeRoot = root;
138
+ renderDropdown(root);
139
+ root.dropdown.classList.remove("hidden");
140
+ positionDropdown(root);
141
+ root.trigger.setAttribute("aria-expanded", "true");
142
+ installDocumentListener();
143
+ }
144
+ function toggleDropdown(root) {
145
+ if (activeRoot && activeRoot === root && !root.dropdown.classList.contains("hidden")) {
146
+ closeDropdown();
147
+ return;
148
+ }
149
+ openDropdown(root);
150
+ }
151
+ function installDocumentListener() {
152
+ if (documentListenerInstalled)
153
+ return;
154
+ documentListenerInstalled = true;
155
+ document.addEventListener("pointerdown", handleDocumentPointerDown);
156
+ }
157
+ function removeDocumentListener() {
158
+ if (!documentListenerInstalled)
159
+ return;
160
+ documentListenerInstalled = false;
161
+ document.removeEventListener("pointerdown", handleDocumentPointerDown);
162
+ }
163
+ function handleDocumentPointerDown(event) {
164
+ if (!activeRoot)
165
+ return;
166
+ const target = event.target;
167
+ if (!target || !activeRoot.root.contains(target)) {
168
+ closeDropdown();
169
+ }
170
+ }
171
+ function closeNotificationsModal() {
172
+ if (!closeModalFn)
173
+ return;
174
+ closeModalFn();
175
+ closeModalFn = null;
176
+ }
177
+ function openNotificationsModal(item, returnFocusTo) {
178
+ const modal = getModalElements();
179
+ if (!modal)
180
+ return;
181
+ closeNotificationsModal();
182
+ const runLabel = item.seq ? `${item.runId.slice(0, 8)} (#${item.seq})` : item.runId.slice(0, 8);
183
+ const modeLabel = item.mode ? ` (${item.mode})` : "";
184
+ const body = item.body?.trim() ? escapeHtml(item.body) : '<span class="muted">No message body.</span>';
185
+ modal.body.innerHTML = `
186
+ <div class="notifications-modal-meta">
187
+ <div class="notifications-modal-row">
188
+ <span class="notifications-modal-label">Repo</span>
189
+ <span class="notifications-modal-value">${escapeHtml(item.repoDisplay)}</span>
190
+ </div>
191
+ <div class="notifications-modal-row">
192
+ <span class="notifications-modal-label">Run</span>
193
+ <span class="notifications-modal-value mono">${escapeHtml(runLabel)}</span>
194
+ </div>
195
+ <div class="notifications-modal-row">
196
+ <span class="notifications-modal-label">Dispatch</span>
197
+ <span class="notifications-modal-value">${escapeHtml(item.title)}${escapeHtml(modeLabel)}</span>
198
+ </div>
199
+ </div>
200
+ <div class="notifications-modal-body">${body}</div>
201
+ <div class="notifications-modal-actions">
202
+ <a class="primary sm notifications-open-run" href="${escapeHtml(resolvePath(item.openUrl))}">Open run</a>
203
+ </div>
204
+ <div class="notifications-modal-placeholder">Reply here (coming soon).</div>
205
+ `;
206
+ closeModalFn = openModal(modal.overlay, {
207
+ closeOnEscape: true,
208
+ closeOnOverlay: true,
209
+ initialFocus: modal.closeBtn,
210
+ returnFocusTo: returnFocusTo || null,
211
+ });
212
+ }
213
+ async function refreshNotifications(_ctx) {
214
+ if (isRefreshing)
215
+ return;
216
+ isRefreshing = true;
217
+ try {
218
+ const payload = (await api("/hub/messages", { method: "GET" }));
219
+ const items = payload?.items || [];
220
+ notificationItems = items.map(normalizeItem);
221
+ setBadgeCount(notificationItems.length);
222
+ if (activeRoot) {
223
+ renderDropdown(activeRoot);
224
+ }
225
+ }
226
+ catch (_err) {
227
+ if (activeRoot) {
228
+ renderDropdownError(activeRoot);
229
+ }
230
+ }
231
+ finally {
232
+ isRefreshing = false;
233
+ }
234
+ }
235
+ function attachRoot(root) {
236
+ root.trigger.setAttribute("aria-haspopup", "menu");
237
+ root.trigger.setAttribute("aria-expanded", "false");
238
+ root.trigger.addEventListener("pointerdown", (event) => {
239
+ event.preventDefault();
240
+ event.stopPropagation();
241
+ toggleDropdown(root);
242
+ });
243
+ root.trigger.addEventListener("click", (event) => {
244
+ event.preventDefault();
245
+ event.stopPropagation();
246
+ });
247
+ root.dropdown.addEventListener("click", (event) => {
248
+ const target = event.target?.closest(".notifications-item");
249
+ if (!target)
250
+ return;
251
+ const index = Number(target.dataset.index || "-1");
252
+ const item = notificationItems[index];
253
+ if (!item)
254
+ return;
255
+ closeDropdown();
256
+ openNotificationsModal(item, root.trigger);
257
+ });
258
+ }
259
+ function attachModalHandlers() {
260
+ const modal = getModalElements();
261
+ if (!modal)
262
+ return;
263
+ modal.closeBtn.addEventListener("click", () => {
264
+ closeNotificationsModal();
265
+ });
266
+ }
267
+ export function initNotifications() {
268
+ if (notificationsInitialized)
269
+ return;
270
+ const roots = Array.from(document.querySelectorAll("[data-notifications-root]"));
271
+ if (!roots.length)
272
+ return;
273
+ roots.forEach((root) => {
274
+ const elements = getRootElements(root);
275
+ if (!elements)
276
+ return;
277
+ attachRoot(elements);
278
+ });
279
+ attachModalHandlers();
280
+ registerAutoRefresh(NOTIFICATIONS_REFRESH_ID, {
281
+ callback: refreshNotifications,
282
+ tabId: null,
283
+ interval: NOTIFICATIONS_REFRESH_MS,
284
+ refreshOnActivation: true,
285
+ immediate: true,
286
+ });
287
+ notificationsInitialized = true;
288
+ }