codex-autorunner 1.1.0__py3-none-any.whl → 1.2.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/agents/opencode/client.py +113 -4
- codex_autorunner/agents/opencode/supervisor.py +4 -0
- codex_autorunner/agents/registry.py +17 -7
- codex_autorunner/bootstrap.py +219 -1
- codex_autorunner/core/__init__.py +17 -1
- codex_autorunner/core/about_car.py +114 -1
- codex_autorunner/core/app_server_threads.py +6 -0
- codex_autorunner/core/config.py +236 -1
- codex_autorunner/core/context_awareness.py +38 -0
- codex_autorunner/core/docs.py +0 -122
- codex_autorunner/core/filebox.py +265 -0
- codex_autorunner/core/flows/controller.py +71 -1
- codex_autorunner/core/flows/reconciler.py +4 -1
- codex_autorunner/core/flows/runtime.py +22 -0
- codex_autorunner/core/flows/store.py +61 -9
- codex_autorunner/core/flows/transition.py +23 -16
- codex_autorunner/core/flows/ux_helpers.py +18 -3
- codex_autorunner/core/flows/worker_process.py +32 -6
- codex_autorunner/core/hub.py +198 -41
- codex_autorunner/core/lifecycle_events.py +253 -0
- codex_autorunner/core/path_utils.py +2 -1
- codex_autorunner/core/pma_audit.py +224 -0
- codex_autorunner/core/pma_context.py +496 -0
- codex_autorunner/core/pma_dispatch_interceptor.py +284 -0
- codex_autorunner/core/pma_lifecycle.py +527 -0
- codex_autorunner/core/pma_queue.py +367 -0
- codex_autorunner/core/pma_safety.py +221 -0
- codex_autorunner/core/pma_state.py +115 -0
- codex_autorunner/core/ports/agent_backend.py +2 -5
- codex_autorunner/core/ports/run_event.py +1 -4
- codex_autorunner/core/prompt.py +0 -80
- codex_autorunner/core/prompts.py +56 -172
- codex_autorunner/core/redaction.py +0 -4
- codex_autorunner/core/review_context.py +11 -9
- codex_autorunner/core/runner_controller.py +35 -33
- codex_autorunner/core/runner_state.py +147 -0
- codex_autorunner/core/runtime.py +829 -0
- codex_autorunner/core/sqlite_utils.py +13 -4
- codex_autorunner/core/state.py +7 -10
- codex_autorunner/core/state_roots.py +5 -0
- codex_autorunner/core/templates/__init__.py +39 -0
- codex_autorunner/core/templates/git_mirror.py +234 -0
- codex_autorunner/core/templates/provenance.py +56 -0
- codex_autorunner/core/templates/scan_cache.py +120 -0
- codex_autorunner/core/ticket_linter_cli.py +17 -0
- codex_autorunner/core/ticket_manager_cli.py +154 -92
- codex_autorunner/core/time_utils.py +11 -0
- codex_autorunner/core/types.py +18 -0
- codex_autorunner/core/utils.py +34 -6
- codex_autorunner/flows/review/service.py +23 -25
- codex_autorunner/flows/ticket_flow/definition.py +43 -1
- codex_autorunner/integrations/agents/__init__.py +2 -0
- codex_autorunner/integrations/agents/backend_orchestrator.py +18 -0
- codex_autorunner/integrations/agents/codex_backend.py +19 -8
- codex_autorunner/integrations/agents/runner.py +3 -8
- codex_autorunner/integrations/agents/wiring.py +8 -0
- codex_autorunner/integrations/telegram/doctor.py +228 -6
- codex_autorunner/integrations/telegram/handlers/commands/execution.py +236 -74
- codex_autorunner/integrations/telegram/handlers/commands/files.py +314 -75
- codex_autorunner/integrations/telegram/handlers/commands/flows.py +346 -58
- codex_autorunner/integrations/telegram/handlers/commands/workspace.py +498 -37
- codex_autorunner/integrations/telegram/handlers/commands_runtime.py +202 -45
- codex_autorunner/integrations/telegram/handlers/commands_spec.py +18 -7
- codex_autorunner/integrations/telegram/handlers/messages.py +26 -1
- codex_autorunner/integrations/telegram/helpers.py +1 -3
- codex_autorunner/integrations/telegram/runtime.py +9 -4
- codex_autorunner/integrations/telegram/service.py +30 -0
- codex_autorunner/integrations/telegram/state.py +38 -0
- codex_autorunner/integrations/telegram/ticket_flow_bridge.py +10 -4
- codex_autorunner/integrations/telegram/transport.py +10 -3
- codex_autorunner/integrations/templates/__init__.py +27 -0
- codex_autorunner/integrations/templates/scan_agent.py +312 -0
- codex_autorunner/server.py +2 -2
- codex_autorunner/static/agentControls.js +21 -5
- codex_autorunner/static/app.js +115 -11
- codex_autorunner/static/chatUploads.js +137 -0
- codex_autorunner/static/docChatCore.js +185 -13
- codex_autorunner/static/fileChat.js +68 -40
- codex_autorunner/static/fileboxUi.js +159 -0
- codex_autorunner/static/hub.js +46 -81
- codex_autorunner/static/index.html +303 -24
- codex_autorunner/static/messages.js +82 -4
- codex_autorunner/static/notifications.js +255 -0
- codex_autorunner/static/pma.js +1167 -0
- codex_autorunner/static/settings.js +3 -0
- codex_autorunner/static/streamUtils.js +57 -0
- codex_autorunner/static/styles.css +9125 -6742
- codex_autorunner/static/templateReposSettings.js +225 -0
- codex_autorunner/static/ticketChatActions.js +165 -3
- codex_autorunner/static/ticketChatStream.js +17 -119
- codex_autorunner/static/ticketEditor.js +41 -13
- codex_autorunner/static/ticketTemplates.js +798 -0
- codex_autorunner/static/tickets.js +69 -19
- codex_autorunner/static/turnEvents.js +27 -0
- codex_autorunner/static/turnResume.js +33 -0
- codex_autorunner/static/utils.js +28 -0
- codex_autorunner/static/workspace.js +258 -44
- codex_autorunner/static/workspaceFileBrowser.js +6 -4
- codex_autorunner/surfaces/cli/cli.py +1465 -155
- codex_autorunner/surfaces/cli/pma_cli.py +817 -0
- codex_autorunner/surfaces/web/app.py +253 -49
- codex_autorunner/surfaces/web/routes/__init__.py +4 -0
- codex_autorunner/surfaces/web/routes/analytics.py +29 -22
- codex_autorunner/surfaces/web/routes/file_chat.py +317 -36
- codex_autorunner/surfaces/web/routes/filebox.py +227 -0
- codex_autorunner/surfaces/web/routes/flows.py +219 -29
- codex_autorunner/surfaces/web/routes/messages.py +70 -39
- codex_autorunner/surfaces/web/routes/pma.py +1652 -0
- codex_autorunner/surfaces/web/routes/repos.py +1 -1
- codex_autorunner/surfaces/web/routes/shared.py +0 -3
- codex_autorunner/surfaces/web/routes/templates.py +634 -0
- codex_autorunner/surfaces/web/runner_manager.py +2 -2
- codex_autorunner/surfaces/web/schemas.py +70 -18
- codex_autorunner/tickets/agent_pool.py +27 -0
- codex_autorunner/tickets/files.py +33 -16
- codex_autorunner/tickets/lint.py +50 -0
- codex_autorunner/tickets/models.py +3 -0
- codex_autorunner/tickets/outbox.py +41 -5
- codex_autorunner/tickets/runner.py +350 -69
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/METADATA +15 -19
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/RECORD +125 -94
- codex_autorunner/core/adapter_utils.py +0 -21
- codex_autorunner/core/engine.py +0 -3302
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/WHEEL +0 -0
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/entry_points.txt +0 -0
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {codex_autorunner-1.1.0.dist-info → codex_autorunner-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ from urllib.parse import quote
|
|
|
27
27
|
import yaml
|
|
28
28
|
from fastapi import APIRouter, File, Form, HTTPException, Request, UploadFile
|
|
29
29
|
|
|
30
|
+
from ....core.filebox import ensure_structure, save_file
|
|
30
31
|
from ....core.flows.models import FlowRunRecord, FlowRunStatus
|
|
31
32
|
from ....core.flows.store import FlowStore
|
|
32
33
|
from ....core.utils import find_repo_root
|
|
@@ -47,15 +48,29 @@ def _flows_db_path(repo_root: Path) -> Path:
|
|
|
47
48
|
return repo_root / ".codex-autorunner" / "flows.db"
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
def _resolve_workspace_and_runs(
|
|
52
|
+
record_input: dict[str, Any], repo_root: Path
|
|
53
|
+
) -> tuple[Path, Path]:
|
|
54
|
+
"""
|
|
55
|
+
Normalize workspace_root/runs_dir with sensible fallbacks.
|
|
56
|
+
|
|
57
|
+
- workspace_root defaults to the current repo_root.
|
|
58
|
+
- runs_dir defaults to .codex-autorunner/runs.
|
|
59
|
+
- If runs_dir is absolute, keep it as-is; otherwise join to workspace_root.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
raw_workspace = record_input.get("workspace_root")
|
|
63
|
+
workspace_root = Path(raw_workspace) if raw_workspace else repo_root
|
|
64
|
+
if not workspace_root.is_absolute():
|
|
65
|
+
workspace_root = (repo_root / workspace_root).resolve()
|
|
66
|
+
else:
|
|
67
|
+
workspace_root = workspace_root.resolve()
|
|
68
|
+
|
|
69
|
+
runs_dir_raw = record_input.get("runs_dir") or ".codex-autorunner/runs"
|
|
70
|
+
runs_dir_path = Path(runs_dir_raw)
|
|
71
|
+
if not runs_dir_path.is_absolute():
|
|
72
|
+
runs_dir_path = (workspace_root / runs_dir_path).resolve()
|
|
73
|
+
return workspace_root, runs_dir_path
|
|
59
74
|
|
|
60
75
|
|
|
61
76
|
def _timestamp(path: Path) -> Optional[str]:
|
|
@@ -103,8 +118,7 @@ def _collect_dispatch_history(
|
|
|
103
118
|
*, repo_root: Path, run_id: str, record_input: dict[str, Any]
|
|
104
119
|
) -> list[dict[str, Any]]:
|
|
105
120
|
"""Collect all dispatches from the dispatch history directory."""
|
|
106
|
-
workspace_root =
|
|
107
|
-
runs_dir = Path(record_input.get("runs_dir") or ".codex-autorunner/runs")
|
|
121
|
+
workspace_root, runs_dir = _resolve_workspace_and_runs(record_input, repo_root)
|
|
108
122
|
outbox_paths = resolve_outbox_paths(
|
|
109
123
|
workspace_root=workspace_root, runs_dir=runs_dir, run_id=run_id
|
|
110
124
|
)
|
|
@@ -161,8 +175,7 @@ def _collect_dispatch_history(
|
|
|
161
175
|
def _collect_reply_history(
|
|
162
176
|
*, repo_root: Path, run_id: str, record_input: dict[str, Any]
|
|
163
177
|
):
|
|
164
|
-
workspace_root =
|
|
165
|
-
runs_dir = Path(record_input.get("runs_dir") or ".codex-autorunner/runs")
|
|
178
|
+
workspace_root, runs_dir = _resolve_workspace_and_runs(record_input, repo_root)
|
|
166
179
|
reply_paths = resolve_reply_paths(
|
|
167
180
|
workspace_root=workspace_root, runs_dir=runs_dir, run_id=run_id
|
|
168
181
|
)
|
|
@@ -236,20 +249,22 @@ def build_messages_routes() -> APIRouter:
|
|
|
236
249
|
|
|
237
250
|
@router.get("/api/messages/active")
|
|
238
251
|
def get_active_message(request: Request):
|
|
252
|
+
from ....core.config import load_repo_config
|
|
253
|
+
|
|
239
254
|
repo_root = find_repo_root()
|
|
240
255
|
db_path = _flows_db_path(repo_root)
|
|
241
256
|
if not db_path.exists():
|
|
242
257
|
return {"active": False}
|
|
243
|
-
store = FlowStore(db_path)
|
|
244
258
|
try:
|
|
245
|
-
|
|
259
|
+
with FlowStore(
|
|
260
|
+
db_path, durable=load_repo_config(repo_root).durable_writes
|
|
261
|
+
) as store:
|
|
262
|
+
paused = store.list_flow_runs(
|
|
263
|
+
flow_type="ticket_flow", status=FlowRunStatus.PAUSED
|
|
264
|
+
)
|
|
246
265
|
except Exception:
|
|
247
266
|
# Corrupt flows db should not 500 the UI.
|
|
248
267
|
return {"active": False}
|
|
249
|
-
|
|
250
|
-
paused = store.list_flow_runs(
|
|
251
|
-
flow_type="ticket_flow", status=FlowRunStatus.PAUSED
|
|
252
|
-
)
|
|
253
268
|
if not paused:
|
|
254
269
|
return {"active": False}
|
|
255
270
|
|
|
@@ -281,16 +296,20 @@ def build_messages_routes() -> APIRouter:
|
|
|
281
296
|
|
|
282
297
|
@router.get("/api/messages/threads")
|
|
283
298
|
def list_threads():
|
|
299
|
+
from ....core.config import load_repo_config
|
|
300
|
+
|
|
284
301
|
repo_root = find_repo_root()
|
|
285
302
|
db_path = _flows_db_path(repo_root)
|
|
286
303
|
if not db_path.exists():
|
|
287
304
|
return {"conversations": []}
|
|
288
|
-
store = FlowStore(db_path)
|
|
289
305
|
try:
|
|
290
|
-
|
|
306
|
+
with FlowStore(
|
|
307
|
+
db_path, durable=load_repo_config(repo_root).durable_writes
|
|
308
|
+
) as store:
|
|
309
|
+
runs = store.list_flow_runs(flow_type="ticket_flow")
|
|
291
310
|
except Exception:
|
|
292
311
|
return {"conversations": []}
|
|
293
|
-
|
|
312
|
+
|
|
294
313
|
conversations: list[dict[str, Any]] = []
|
|
295
314
|
for record in runs:
|
|
296
315
|
record_input = dict(record.input_data or {})
|
|
@@ -327,6 +346,8 @@ def build_messages_routes() -> APIRouter:
|
|
|
327
346
|
|
|
328
347
|
@router.get("/api/messages/threads/{run_id}")
|
|
329
348
|
def get_thread(run_id: str):
|
|
349
|
+
from ....core.config import load_repo_config
|
|
350
|
+
|
|
330
351
|
repo_root = find_repo_root()
|
|
331
352
|
db_path = _flows_db_path(repo_root)
|
|
332
353
|
empty_response = {
|
|
@@ -337,14 +358,15 @@ def build_messages_routes() -> APIRouter:
|
|
|
337
358
|
}
|
|
338
359
|
if not db_path.exists():
|
|
339
360
|
return empty_response
|
|
340
|
-
store = _load_store_or_404(db_path)
|
|
341
361
|
try:
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
store.
|
|
346
|
-
|
|
347
|
-
|
|
362
|
+
with FlowStore(
|
|
363
|
+
db_path, durable=load_repo_config(repo_root).durable_writes
|
|
364
|
+
) as store:
|
|
365
|
+
record = store.get_flow_run(run_id)
|
|
366
|
+
except Exception:
|
|
367
|
+
raise HTTPException(
|
|
368
|
+
status_code=404, detail="Flows database unavailable"
|
|
369
|
+
) from None
|
|
348
370
|
if not record:
|
|
349
371
|
return empty_response
|
|
350
372
|
input_data = dict(record.input_data or {})
|
|
@@ -378,29 +400,31 @@ def build_messages_routes() -> APIRouter:
|
|
|
378
400
|
body: str = Form(""),
|
|
379
401
|
title: Optional[str] = Form(None),
|
|
380
402
|
# NOTE: FastAPI/starlette will supply either a single UploadFile or a list
|
|
381
|
-
# depending on how
|
|
403
|
+
# depending on how is multipart form is encoded. Declaring this as a
|
|
382
404
|
# concrete list avoids a common 422 where a single file upload is treated
|
|
383
405
|
# as a non-list value.
|
|
384
406
|
files: list[UploadFile] = File(default=[]), # noqa: B006,B008
|
|
385
407
|
):
|
|
408
|
+
from ....core.config import load_repo_config
|
|
409
|
+
|
|
386
410
|
repo_root = find_repo_root()
|
|
387
411
|
db_path = _flows_db_path(repo_root)
|
|
388
412
|
if not db_path.exists():
|
|
389
413
|
raise HTTPException(status_code=404, detail="No flows database")
|
|
390
|
-
store = _load_store_or_404(db_path)
|
|
391
414
|
try:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
store.
|
|
396
|
-
|
|
397
|
-
|
|
415
|
+
with FlowStore(
|
|
416
|
+
db_path, durable=load_repo_config(repo_root).durable_writes
|
|
417
|
+
) as store:
|
|
418
|
+
record = store.get_flow_run(run_id)
|
|
419
|
+
except Exception:
|
|
420
|
+
raise HTTPException(
|
|
421
|
+
status_code=404, detail="Flows database unavailable"
|
|
422
|
+
) from None
|
|
398
423
|
if not record:
|
|
399
424
|
raise HTTPException(status_code=404, detail="Run not found")
|
|
400
425
|
|
|
401
426
|
input_data = dict(record.input_data or {})
|
|
402
|
-
workspace_root =
|
|
403
|
-
runs_dir = Path(input_data.get("runs_dir") or ".codex-autorunner/runs")
|
|
427
|
+
workspace_root, runs_dir = _resolve_workspace_and_runs(input_data, repo_root)
|
|
404
428
|
reply_paths = resolve_reply_paths(
|
|
405
429
|
workspace_root=workspace_root, runs_dir=runs_dir, run_id=run_id
|
|
406
430
|
)
|
|
@@ -436,6 +460,13 @@ def build_messages_routes() -> APIRouter:
|
|
|
436
460
|
data = await upload.read()
|
|
437
461
|
try:
|
|
438
462
|
dest.write_bytes(data)
|
|
463
|
+
try:
|
|
464
|
+
ensure_structure(repo_root)
|
|
465
|
+
save_file(repo_root, "inbox", filename, data)
|
|
466
|
+
except Exception:
|
|
467
|
+
_logger.debug(
|
|
468
|
+
"Failed to mirror attachment into FileBox", exc_info=True
|
|
469
|
+
)
|
|
439
470
|
except OSError as exc:
|
|
440
471
|
raise HTTPException(
|
|
441
472
|
status_code=500, detail=f"Failed to write attachment: {exc}"
|