codex-autorunner 1.0.0__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.
- codex_autorunner/__init__.py +12 -1
- codex_autorunner/agents/codex/harness.py +1 -1
- codex_autorunner/agents/opencode/constants.py +3 -0
- codex_autorunner/agents/opencode/harness.py +6 -1
- codex_autorunner/agents/opencode/runtime.py +59 -18
- codex_autorunner/agents/registry.py +22 -3
- codex_autorunner/bootstrap.py +7 -3
- codex_autorunner/cli.py +5 -1174
- codex_autorunner/codex_cli.py +20 -84
- codex_autorunner/core/__init__.py +4 -0
- codex_autorunner/core/about_car.py +6 -1
- codex_autorunner/core/app_server_ids.py +59 -0
- codex_autorunner/core/app_server_threads.py +11 -2
- codex_autorunner/core/app_server_utils.py +165 -0
- codex_autorunner/core/archive.py +349 -0
- codex_autorunner/core/codex_runner.py +6 -2
- codex_autorunner/core/config.py +197 -3
- codex_autorunner/core/drafts.py +58 -4
- codex_autorunner/core/engine.py +1329 -680
- codex_autorunner/core/exceptions.py +4 -0
- codex_autorunner/core/flows/controller.py +25 -1
- codex_autorunner/core/flows/models.py +13 -0
- codex_autorunner/core/flows/reasons.py +52 -0
- codex_autorunner/core/flows/reconciler.py +131 -0
- codex_autorunner/core/flows/runtime.py +35 -4
- codex_autorunner/core/flows/store.py +83 -0
- codex_autorunner/core/flows/transition.py +5 -0
- codex_autorunner/core/flows/ux_helpers.py +257 -0
- codex_autorunner/core/git_utils.py +62 -0
- codex_autorunner/core/hub.py +121 -7
- codex_autorunner/core/notifications.py +14 -2
- codex_autorunner/core/ports/__init__.py +28 -0
- codex_autorunner/{integrations/agents → core/ports}/agent_backend.py +11 -3
- codex_autorunner/core/ports/backend_orchestrator.py +41 -0
- codex_autorunner/{integrations/agents → core/ports}/run_event.py +22 -2
- codex_autorunner/core/state_roots.py +57 -0
- codex_autorunner/core/supervisor_protocol.py +15 -0
- codex_autorunner/core/text_delta_coalescer.py +54 -0
- codex_autorunner/core/ticket_linter_cli.py +201 -0
- codex_autorunner/core/ticket_manager_cli.py +432 -0
- codex_autorunner/core/update.py +4 -5
- codex_autorunner/core/update_paths.py +28 -0
- codex_autorunner/core/usage.py +164 -12
- codex_autorunner/core/utils.py +91 -9
- codex_autorunner/flows/review/__init__.py +17 -0
- codex_autorunner/{core/review.py → flows/review/service.py} +15 -10
- codex_autorunner/flows/ticket_flow/definition.py +9 -2
- codex_autorunner/integrations/agents/__init__.py +9 -19
- codex_autorunner/integrations/agents/backend_orchestrator.py +284 -0
- codex_autorunner/integrations/agents/codex_adapter.py +90 -0
- codex_autorunner/integrations/agents/codex_backend.py +158 -17
- codex_autorunner/integrations/agents/opencode_adapter.py +108 -0
- codex_autorunner/integrations/agents/opencode_backend.py +305 -32
- codex_autorunner/integrations/agents/runner.py +91 -0
- codex_autorunner/integrations/agents/wiring.py +271 -0
- codex_autorunner/integrations/app_server/client.py +7 -60
- codex_autorunner/integrations/app_server/env.py +2 -107
- codex_autorunner/{core/app_server_events.py → integrations/app_server/event_buffer.py} +15 -8
- codex_autorunner/integrations/telegram/adapter.py +65 -0
- codex_autorunner/integrations/telegram/config.py +46 -0
- codex_autorunner/integrations/telegram/constants.py +1 -1
- codex_autorunner/integrations/telegram/handlers/callbacks.py +7 -0
- codex_autorunner/integrations/telegram/handlers/commands/flows.py +1203 -66
- codex_autorunner/integrations/telegram/handlers/commands_runtime.py +4 -3
- codex_autorunner/integrations/telegram/handlers/commands_spec.py +8 -2
- codex_autorunner/integrations/telegram/handlers/messages.py +1 -0
- codex_autorunner/integrations/telegram/handlers/selections.py +61 -1
- codex_autorunner/integrations/telegram/helpers.py +24 -1
- codex_autorunner/integrations/telegram/service.py +15 -10
- codex_autorunner/integrations/telegram/ticket_flow_bridge.py +329 -40
- codex_autorunner/integrations/telegram/transport.py +3 -1
- codex_autorunner/routes/__init__.py +37 -76
- codex_autorunner/routes/agents.py +2 -137
- codex_autorunner/routes/analytics.py +2 -238
- codex_autorunner/routes/app_server.py +2 -131
- codex_autorunner/routes/base.py +2 -596
- codex_autorunner/routes/file_chat.py +4 -833
- codex_autorunner/routes/flows.py +4 -977
- codex_autorunner/routes/messages.py +4 -456
- codex_autorunner/routes/repos.py +2 -196
- codex_autorunner/routes/review.py +2 -147
- codex_autorunner/routes/sessions.py +2 -175
- codex_autorunner/routes/settings.py +2 -168
- codex_autorunner/routes/shared.py +2 -275
- codex_autorunner/routes/system.py +4 -193
- codex_autorunner/routes/usage.py +2 -86
- codex_autorunner/routes/voice.py +2 -119
- codex_autorunner/routes/workspace.py +2 -270
- codex_autorunner/server.py +2 -2
- codex_autorunner/static/agentControls.js +40 -11
- codex_autorunner/static/app.js +11 -3
- codex_autorunner/static/archive.js +826 -0
- codex_autorunner/static/archiveApi.js +37 -0
- codex_autorunner/static/autoRefresh.js +7 -7
- codex_autorunner/static/dashboard.js +224 -171
- codex_autorunner/static/hub.js +112 -94
- codex_autorunner/static/index.html +80 -33
- codex_autorunner/static/messages.js +486 -83
- codex_autorunner/static/preserve.js +17 -0
- codex_autorunner/static/settings.js +125 -6
- codex_autorunner/static/smartRefresh.js +52 -0
- codex_autorunner/static/styles.css +1373 -101
- codex_autorunner/static/tabs.js +152 -11
- codex_autorunner/static/terminal.js +18 -0
- codex_autorunner/static/ticketEditor.js +99 -5
- codex_autorunner/static/tickets.js +760 -87
- codex_autorunner/static/utils.js +11 -0
- codex_autorunner/static/workspace.js +133 -40
- codex_autorunner/static/workspaceFileBrowser.js +9 -9
- codex_autorunner/surfaces/__init__.py +5 -0
- codex_autorunner/surfaces/cli/__init__.py +6 -0
- codex_autorunner/surfaces/cli/cli.py +1224 -0
- codex_autorunner/surfaces/cli/codex_cli.py +20 -0
- codex_autorunner/surfaces/telegram/__init__.py +3 -0
- codex_autorunner/surfaces/web/__init__.py +1 -0
- codex_autorunner/surfaces/web/app.py +2019 -0
- codex_autorunner/surfaces/web/hub_jobs.py +192 -0
- codex_autorunner/surfaces/web/middleware.py +587 -0
- codex_autorunner/surfaces/web/pty_session.py +370 -0
- codex_autorunner/surfaces/web/review.py +6 -0
- codex_autorunner/surfaces/web/routes/__init__.py +78 -0
- codex_autorunner/surfaces/web/routes/agents.py +138 -0
- codex_autorunner/surfaces/web/routes/analytics.py +277 -0
- codex_autorunner/surfaces/web/routes/app_server.py +132 -0
- codex_autorunner/surfaces/web/routes/archive.py +357 -0
- codex_autorunner/surfaces/web/routes/base.py +615 -0
- codex_autorunner/surfaces/web/routes/file_chat.py +836 -0
- codex_autorunner/surfaces/web/routes/flows.py +1164 -0
- codex_autorunner/surfaces/web/routes/messages.py +459 -0
- codex_autorunner/surfaces/web/routes/repos.py +197 -0
- codex_autorunner/surfaces/web/routes/review.py +148 -0
- codex_autorunner/surfaces/web/routes/sessions.py +176 -0
- codex_autorunner/surfaces/web/routes/settings.py +169 -0
- codex_autorunner/surfaces/web/routes/shared.py +280 -0
- codex_autorunner/surfaces/web/routes/system.py +196 -0
- codex_autorunner/surfaces/web/routes/usage.py +89 -0
- codex_autorunner/surfaces/web/routes/voice.py +120 -0
- codex_autorunner/surfaces/web/routes/workspace.py +271 -0
- codex_autorunner/surfaces/web/runner_manager.py +25 -0
- codex_autorunner/surfaces/web/schemas.py +417 -0
- codex_autorunner/surfaces/web/static_assets.py +490 -0
- codex_autorunner/surfaces/web/static_refresh.py +86 -0
- codex_autorunner/surfaces/web/terminal_sessions.py +78 -0
- codex_autorunner/tickets/__init__.py +8 -1
- codex_autorunner/tickets/agent_pool.py +26 -4
- codex_autorunner/tickets/files.py +6 -2
- codex_autorunner/tickets/models.py +3 -1
- codex_autorunner/tickets/outbox.py +12 -0
- codex_autorunner/tickets/runner.py +63 -5
- codex_autorunner/web/__init__.py +5 -1
- codex_autorunner/web/app.py +2 -1949
- codex_autorunner/web/hub_jobs.py +2 -191
- codex_autorunner/web/middleware.py +2 -586
- codex_autorunner/web/pty_session.py +2 -369
- codex_autorunner/web/runner_manager.py +2 -24
- codex_autorunner/web/schemas.py +2 -376
- codex_autorunner/web/static_assets.py +4 -441
- codex_autorunner/web/static_refresh.py +2 -85
- codex_autorunner/web/terminal_sessions.py +2 -77
- codex_autorunner/workspace/paths.py +49 -33
- codex_autorunner-1.1.0.dist-info/METADATA +154 -0
- codex_autorunner-1.1.0.dist-info/RECORD +308 -0
- codex_autorunner/core/static_assets.py +0 -55
- codex_autorunner-1.0.0.dist-info/METADATA +0 -246
- codex_autorunner-1.0.0.dist-info/RECORD +0 -251
- /codex_autorunner/{routes → surfaces/web/routes}/terminal_images.py +0 -0
- {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/WHEEL +0 -0
- {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/entry_points.txt +0 -0
- {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.1.0.dist-info}/top_level.txt +0 -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,5 +1,5 @@
|
|
|
1
1
|
// GENERATED FILE - do not edit directly. Source: static_src/
|
|
2
|
-
import { api, confirmModal, flash, resolvePath } from "./utils.js";
|
|
2
|
+
import { api, confirmModal, flash, resolvePath, openModal } from "./utils.js";
|
|
3
3
|
const ui = {
|
|
4
4
|
settingsBtn: document.getElementById("repo-settings"),
|
|
5
5
|
threadList: document.getElementById("thread-tools-list"),
|
|
@@ -73,11 +73,9 @@ async function refreshSettings() {
|
|
|
73
73
|
await loadThreadTools();
|
|
74
74
|
}
|
|
75
75
|
export function initRepoSettingsPanel() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
}
|
|
76
|
+
window.__CAR_SETTINGS = { loadThreadTools, refreshSettings };
|
|
77
|
+
// Initialize the modal interaction
|
|
78
|
+
initRepoSettingsModal();
|
|
81
79
|
if (ui.threadNew) {
|
|
82
80
|
ui.threadNew.addEventListener("click", async () => {
|
|
83
81
|
try {
|
|
@@ -152,3 +150,124 @@ export function initRepoSettingsPanel() {
|
|
|
152
150
|
// ignore
|
|
153
151
|
}
|
|
154
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
|
+
}
|
|
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
|
+
}
|