codex-autorunner 0.1.2__py3-none-any.whl → 1.0.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/__main__.py +4 -0
- codex_autorunner/agents/opencode/client.py +68 -35
- codex_autorunner/agents/opencode/logging.py +21 -5
- codex_autorunner/agents/opencode/run_prompt.py +1 -0
- codex_autorunner/agents/opencode/runtime.py +118 -30
- codex_autorunner/agents/opencode/supervisor.py +36 -48
- codex_autorunner/agents/registry.py +136 -8
- codex_autorunner/api.py +25 -0
- codex_autorunner/bootstrap.py +16 -35
- codex_autorunner/cli.py +157 -139
- codex_autorunner/core/about_car.py +44 -32
- codex_autorunner/core/adapter_utils.py +21 -0
- codex_autorunner/core/app_server_logging.py +7 -3
- codex_autorunner/core/app_server_prompts.py +27 -260
- codex_autorunner/core/app_server_threads.py +15 -26
- codex_autorunner/core/codex_runner.py +6 -0
- codex_autorunner/core/config.py +390 -100
- codex_autorunner/core/docs.py +10 -2
- codex_autorunner/core/drafts.py +82 -0
- codex_autorunner/core/engine.py +278 -262
- codex_autorunner/core/flows/__init__.py +25 -0
- codex_autorunner/core/flows/controller.py +178 -0
- codex_autorunner/core/flows/definition.py +82 -0
- codex_autorunner/core/flows/models.py +75 -0
- codex_autorunner/core/flows/runtime.py +351 -0
- codex_autorunner/core/flows/store.py +485 -0
- codex_autorunner/core/flows/transition.py +133 -0
- codex_autorunner/core/flows/worker_process.py +242 -0
- codex_autorunner/core/hub.py +15 -9
- codex_autorunner/core/locks.py +4 -0
- codex_autorunner/core/prompt.py +15 -7
- codex_autorunner/core/redaction.py +29 -0
- codex_autorunner/core/review_context.py +5 -8
- codex_autorunner/core/run_index.py +6 -0
- codex_autorunner/core/runner_process.py +5 -2
- codex_autorunner/core/state.py +0 -88
- codex_autorunner/core/static_assets.py +55 -0
- codex_autorunner/core/supervisor_utils.py +67 -0
- codex_autorunner/core/update.py +20 -11
- codex_autorunner/core/update_runner.py +2 -0
- codex_autorunner/core/utils.py +29 -2
- codex_autorunner/discovery.py +2 -4
- codex_autorunner/flows/ticket_flow/__init__.py +3 -0
- codex_autorunner/flows/ticket_flow/definition.py +91 -0
- codex_autorunner/integrations/agents/__init__.py +27 -0
- codex_autorunner/integrations/agents/agent_backend.py +142 -0
- codex_autorunner/integrations/agents/codex_backend.py +307 -0
- codex_autorunner/integrations/agents/opencode_backend.py +325 -0
- codex_autorunner/integrations/agents/run_event.py +71 -0
- codex_autorunner/integrations/app_server/client.py +576 -92
- codex_autorunner/integrations/app_server/supervisor.py +59 -33
- codex_autorunner/integrations/telegram/adapter.py +141 -167
- codex_autorunner/integrations/telegram/api_schemas.py +120 -0
- codex_autorunner/integrations/telegram/config.py +175 -0
- codex_autorunner/integrations/telegram/constants.py +16 -1
- codex_autorunner/integrations/telegram/dispatch.py +17 -0
- codex_autorunner/integrations/telegram/doctor.py +47 -0
- codex_autorunner/integrations/telegram/handlers/callbacks.py +0 -4
- codex_autorunner/integrations/telegram/handlers/commands/__init__.py +2 -0
- codex_autorunner/integrations/telegram/handlers/commands/execution.py +53 -57
- codex_autorunner/integrations/telegram/handlers/commands/files.py +2 -6
- codex_autorunner/integrations/telegram/handlers/commands/flows.py +227 -0
- codex_autorunner/integrations/telegram/handlers/commands/formatting.py +1 -1
- codex_autorunner/integrations/telegram/handlers/commands/github.py +41 -582
- codex_autorunner/integrations/telegram/handlers/commands/workspace.py +8 -8
- codex_autorunner/integrations/telegram/handlers/commands_runtime.py +133 -475
- codex_autorunner/integrations/telegram/handlers/commands_spec.py +11 -4
- codex_autorunner/integrations/telegram/handlers/messages.py +120 -9
- codex_autorunner/integrations/telegram/helpers.py +88 -16
- codex_autorunner/integrations/telegram/outbox.py +208 -37
- codex_autorunner/integrations/telegram/progress_stream.py +3 -10
- codex_autorunner/integrations/telegram/service.py +214 -40
- codex_autorunner/integrations/telegram/state.py +100 -2
- codex_autorunner/integrations/telegram/ticket_flow_bridge.py +322 -0
- codex_autorunner/integrations/telegram/transport.py +36 -3
- codex_autorunner/integrations/telegram/trigger_mode.py +53 -0
- codex_autorunner/manifest.py +2 -0
- codex_autorunner/plugin_api.py +22 -0
- codex_autorunner/routes/__init__.py +23 -14
- codex_autorunner/routes/analytics.py +239 -0
- codex_autorunner/routes/base.py +81 -109
- codex_autorunner/routes/file_chat.py +836 -0
- codex_autorunner/routes/flows.py +980 -0
- codex_autorunner/routes/messages.py +459 -0
- codex_autorunner/routes/system.py +6 -1
- codex_autorunner/routes/usage.py +87 -0
- codex_autorunner/routes/workspace.py +271 -0
- codex_autorunner/server.py +2 -1
- codex_autorunner/static/agentControls.js +1 -0
- codex_autorunner/static/agentEvents.js +248 -0
- codex_autorunner/static/app.js +25 -22
- codex_autorunner/static/autoRefresh.js +29 -1
- codex_autorunner/static/bootstrap.js +1 -0
- codex_autorunner/static/bus.js +1 -0
- codex_autorunner/static/cache.js +1 -0
- codex_autorunner/static/constants.js +20 -4
- codex_autorunner/static/dashboard.js +162 -196
- codex_autorunner/static/diffRenderer.js +37 -0
- codex_autorunner/static/docChatCore.js +324 -0
- codex_autorunner/static/docChatStorage.js +65 -0
- codex_autorunner/static/docChatVoice.js +65 -0
- codex_autorunner/static/docEditor.js +133 -0
- codex_autorunner/static/env.js +1 -0
- codex_autorunner/static/eventSummarizer.js +166 -0
- codex_autorunner/static/fileChat.js +182 -0
- codex_autorunner/static/health.js +155 -0
- codex_autorunner/static/hub.js +41 -118
- codex_autorunner/static/index.html +787 -858
- codex_autorunner/static/liveUpdates.js +1 -0
- codex_autorunner/static/loader.js +1 -0
- codex_autorunner/static/messages.js +470 -0
- codex_autorunner/static/mobileCompact.js +2 -1
- codex_autorunner/static/settings.js +24 -211
- codex_autorunner/static/styles.css +7567 -3865
- codex_autorunner/static/tabs.js +28 -5
- codex_autorunner/static/terminal.js +14 -0
- codex_autorunner/static/terminalManager.js +34 -59
- codex_autorunner/static/ticketChatActions.js +333 -0
- codex_autorunner/static/ticketChatEvents.js +16 -0
- codex_autorunner/static/ticketChatStorage.js +16 -0
- codex_autorunner/static/ticketChatStream.js +264 -0
- codex_autorunner/static/ticketEditor.js +750 -0
- codex_autorunner/static/ticketVoice.js +9 -0
- codex_autorunner/static/tickets.js +1315 -0
- codex_autorunner/static/utils.js +32 -3
- codex_autorunner/static/voice.js +1 -0
- codex_autorunner/static/workspace.js +672 -0
- codex_autorunner/static/workspaceApi.js +53 -0
- codex_autorunner/static/workspaceFileBrowser.js +504 -0
- codex_autorunner/tickets/__init__.py +20 -0
- codex_autorunner/tickets/agent_pool.py +377 -0
- codex_autorunner/tickets/files.py +85 -0
- codex_autorunner/tickets/frontmatter.py +55 -0
- codex_autorunner/tickets/lint.py +102 -0
- codex_autorunner/tickets/models.py +95 -0
- codex_autorunner/tickets/outbox.py +232 -0
- codex_autorunner/tickets/replies.py +179 -0
- codex_autorunner/tickets/runner.py +823 -0
- codex_autorunner/tickets/spec_ingest.py +77 -0
- codex_autorunner/web/app.py +269 -91
- codex_autorunner/web/middleware.py +3 -4
- codex_autorunner/web/schemas.py +89 -109
- codex_autorunner/web/static_assets.py +1 -44
- codex_autorunner/workspace/__init__.py +40 -0
- codex_autorunner/workspace/paths.py +319 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/METADATA +18 -21
- codex_autorunner-1.0.0.dist-info/RECORD +251 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/WHEEL +1 -1
- codex_autorunner/agents/execution/policy.py +0 -292
- codex_autorunner/agents/factory.py +0 -52
- codex_autorunner/agents/orchestrator.py +0 -358
- codex_autorunner/core/doc_chat.py +0 -1446
- codex_autorunner/core/snapshot.py +0 -580
- codex_autorunner/integrations/github/chatops.py +0 -268
- codex_autorunner/integrations/github/pr_flow.py +0 -1314
- codex_autorunner/routes/docs.py +0 -381
- codex_autorunner/routes/github.py +0 -327
- codex_autorunner/routes/runs.py +0 -250
- codex_autorunner/spec_ingest.py +0 -812
- codex_autorunner/static/docChatActions.js +0 -287
- codex_autorunner/static/docChatEvents.js +0 -300
- codex_autorunner/static/docChatRender.js +0 -205
- codex_autorunner/static/docChatStream.js +0 -361
- codex_autorunner/static/docs.js +0 -20
- codex_autorunner/static/docsClipboard.js +0 -69
- codex_autorunner/static/docsCrud.js +0 -257
- codex_autorunner/static/docsDocUpdates.js +0 -62
- codex_autorunner/static/docsDrafts.js +0 -16
- codex_autorunner/static/docsElements.js +0 -69
- codex_autorunner/static/docsInit.js +0 -285
- codex_autorunner/static/docsParse.js +0 -160
- codex_autorunner/static/docsSnapshot.js +0 -87
- codex_autorunner/static/docsSpecIngest.js +0 -263
- codex_autorunner/static/docsState.js +0 -127
- codex_autorunner/static/docsThreadRegistry.js +0 -44
- codex_autorunner/static/docsUi.js +0 -153
- codex_autorunner/static/docsVoice.js +0 -56
- codex_autorunner/static/github.js +0 -504
- codex_autorunner/static/logs.js +0 -678
- codex_autorunner/static/review.js +0 -157
- codex_autorunner/static/runs.js +0 -418
- codex_autorunner/static/snapshot.js +0 -124
- codex_autorunner/static/state.js +0 -94
- codex_autorunner/static/todoPreview.js +0 -27
- codex_autorunner/workspace.py +0 -16
- codex_autorunner-0.1.2.dist-info/RECORD +0 -222
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/entry_points.txt +0 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/top_level.txt +0 -0
codex_autorunner/routes/docs.py
DELETED
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Document management routes: read/write docs and chat functionality.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
|
-
from fastapi import APIRouter, HTTPException, Request
|
|
9
|
-
from fastapi.responses import StreamingResponse
|
|
10
|
-
|
|
11
|
-
from ..core.doc_chat import (
|
|
12
|
-
DocChatBusyError,
|
|
13
|
-
DocChatConflictError,
|
|
14
|
-
DocChatError,
|
|
15
|
-
DocChatValidationError,
|
|
16
|
-
_normalize_kind,
|
|
17
|
-
)
|
|
18
|
-
from ..core.snapshot import (
|
|
19
|
-
SnapshotError,
|
|
20
|
-
load_snapshot,
|
|
21
|
-
load_snapshot_state,
|
|
22
|
-
)
|
|
23
|
-
from ..core.usage import (
|
|
24
|
-
UsageError,
|
|
25
|
-
default_codex_home,
|
|
26
|
-
get_repo_usage_series_cached,
|
|
27
|
-
get_repo_usage_summary_cached,
|
|
28
|
-
parse_iso_datetime,
|
|
29
|
-
)
|
|
30
|
-
from ..core.utils import atomic_write
|
|
31
|
-
from ..spec_ingest import (
|
|
32
|
-
SpecIngestError,
|
|
33
|
-
clear_work_docs,
|
|
34
|
-
)
|
|
35
|
-
from ..web.schemas import (
|
|
36
|
-
DocChatPayload,
|
|
37
|
-
DocContentRequest,
|
|
38
|
-
DocsResponse,
|
|
39
|
-
DocWriteResponse,
|
|
40
|
-
IngestSpecRequest,
|
|
41
|
-
IngestSpecResponse,
|
|
42
|
-
RepoUsageResponse,
|
|
43
|
-
SnapshotCreateResponse,
|
|
44
|
-
SnapshotRequest,
|
|
45
|
-
SnapshotResponse,
|
|
46
|
-
UsageSeriesResponse,
|
|
47
|
-
)
|
|
48
|
-
from .shared import SSE_HEADERS
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def build_docs_routes() -> APIRouter:
|
|
52
|
-
"""Build routes for document management and chat."""
|
|
53
|
-
router = APIRouter()
|
|
54
|
-
|
|
55
|
-
@router.get("/api/docs", response_model=DocsResponse)
|
|
56
|
-
def get_docs(request: Request):
|
|
57
|
-
engine = request.app.state.engine
|
|
58
|
-
return {
|
|
59
|
-
"todo": engine.docs.read_doc("todo"),
|
|
60
|
-
"progress": engine.docs.read_doc("progress"),
|
|
61
|
-
"opinions": engine.docs.read_doc("opinions"),
|
|
62
|
-
"spec": engine.docs.read_doc("spec"),
|
|
63
|
-
"summary": engine.docs.read_doc("summary"),
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@router.put("/api/docs/{kind}", response_model=DocWriteResponse)
|
|
67
|
-
def put_doc(kind: str, payload: DocContentRequest, request: Request):
|
|
68
|
-
engine = request.app.state.engine
|
|
69
|
-
key = kind.lower()
|
|
70
|
-
if key not in ("todo", "progress", "opinions", "spec", "summary"):
|
|
71
|
-
raise HTTPException(status_code=400, detail="invalid doc kind")
|
|
72
|
-
content = payload.content
|
|
73
|
-
atomic_write(engine.config.doc_path(key), content)
|
|
74
|
-
return {"kind": key, "content": content}
|
|
75
|
-
|
|
76
|
-
@router.get("/api/snapshot", response_model=SnapshotResponse)
|
|
77
|
-
def get_snapshot(request: Request):
|
|
78
|
-
engine = request.app.state.engine
|
|
79
|
-
content = load_snapshot(engine)
|
|
80
|
-
state = load_snapshot_state(engine)
|
|
81
|
-
return {"exists": bool(content), "content": content or "", "state": state or {}}
|
|
82
|
-
|
|
83
|
-
@router.post("/api/snapshot", response_model=SnapshotCreateResponse)
|
|
84
|
-
async def post_snapshot(
|
|
85
|
-
request: Request, payload: Optional[SnapshotRequest] = None
|
|
86
|
-
):
|
|
87
|
-
# Snapshot generation has a single default behavior now; we accept an
|
|
88
|
-
# optional JSON object for backwards compatibility, but ignore any fields.
|
|
89
|
-
snapshot_service = request.app.state.snapshot_service
|
|
90
|
-
try:
|
|
91
|
-
result = await snapshot_service.generate_snapshot()
|
|
92
|
-
except SnapshotError as exc:
|
|
93
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
94
|
-
except Exception as exc:
|
|
95
|
-
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
"content": result.content,
|
|
99
|
-
"truncated": result.truncated,
|
|
100
|
-
"state": result.state,
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async def _handle_doc_chat_request(
|
|
104
|
-
request: Request,
|
|
105
|
-
*,
|
|
106
|
-
kind: Optional[str],
|
|
107
|
-
payload: Optional[DocChatPayload],
|
|
108
|
-
):
|
|
109
|
-
doc_chat = request.app.state.doc_chat
|
|
110
|
-
repo_blocked = doc_chat.repo_blocked_reason()
|
|
111
|
-
if repo_blocked:
|
|
112
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
113
|
-
try:
|
|
114
|
-
payload_dict = payload.model_dump(exclude_none=True) if payload else None
|
|
115
|
-
doc_req = doc_chat.parse_request(payload_dict, kind=kind)
|
|
116
|
-
except DocChatValidationError as exc:
|
|
117
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
118
|
-
|
|
119
|
-
if doc_chat.doc_busy():
|
|
120
|
-
raise HTTPException(
|
|
121
|
-
status_code=409,
|
|
122
|
-
detail="Doc chat already running",
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
if doc_req.stream:
|
|
126
|
-
return StreamingResponse(
|
|
127
|
-
doc_chat.stream(doc_req),
|
|
128
|
-
media_type="text/event-stream",
|
|
129
|
-
headers=SSE_HEADERS,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
try:
|
|
133
|
-
async with doc_chat.doc_lock():
|
|
134
|
-
result = await doc_chat.execute(doc_req)
|
|
135
|
-
except DocChatBusyError as exc:
|
|
136
|
-
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
137
|
-
|
|
138
|
-
if result.get("status") != "ok":
|
|
139
|
-
detail = result.get("detail") or "Doc chat failed"
|
|
140
|
-
raise HTTPException(status_code=500, detail=detail)
|
|
141
|
-
return result
|
|
142
|
-
|
|
143
|
-
@router.post("/api/docs/chat")
|
|
144
|
-
async def chat_docs(request: Request, payload: Optional[DocChatPayload] = None):
|
|
145
|
-
return await _handle_doc_chat_request(request, kind=None, payload=payload)
|
|
146
|
-
|
|
147
|
-
@router.post("/api/docs/{kind}/chat")
|
|
148
|
-
async def chat_doc(
|
|
149
|
-
kind: str, request: Request, payload: Optional[DocChatPayload] = None
|
|
150
|
-
):
|
|
151
|
-
return await _handle_doc_chat_request(request, kind=kind, payload=payload)
|
|
152
|
-
|
|
153
|
-
@router.post("/api/docs/chat/interrupt")
|
|
154
|
-
async def interrupt_chat(request: Request):
|
|
155
|
-
doc_chat = request.app.state.doc_chat
|
|
156
|
-
try:
|
|
157
|
-
return await doc_chat.interrupt()
|
|
158
|
-
except DocChatValidationError as exc:
|
|
159
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
160
|
-
|
|
161
|
-
@router.post("/api/docs/{kind}/chat/interrupt")
|
|
162
|
-
async def interrupt_chat_kind(kind: str, request: Request):
|
|
163
|
-
doc_chat = request.app.state.doc_chat
|
|
164
|
-
try:
|
|
165
|
-
return await doc_chat.interrupt(kind)
|
|
166
|
-
except DocChatValidationError as exc:
|
|
167
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
168
|
-
|
|
169
|
-
@router.post("/api/docs/{kind}/chat/apply")
|
|
170
|
-
async def apply_chat_patch(kind: str, request: Request):
|
|
171
|
-
doc_chat = request.app.state.doc_chat
|
|
172
|
-
key = _normalize_kind(kind)
|
|
173
|
-
repo_blocked = doc_chat.repo_blocked_reason()
|
|
174
|
-
if repo_blocked:
|
|
175
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
176
|
-
|
|
177
|
-
try:
|
|
178
|
-
async with doc_chat.doc_lock(key):
|
|
179
|
-
pending = doc_chat.pending_patch(key)
|
|
180
|
-
content = doc_chat.apply_saved_patch(key)
|
|
181
|
-
except DocChatBusyError as exc:
|
|
182
|
-
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
183
|
-
except DocChatConflictError as exc:
|
|
184
|
-
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
185
|
-
except DocChatError as exc:
|
|
186
|
-
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
|
187
|
-
return {
|
|
188
|
-
"status": "ok",
|
|
189
|
-
"kind": key,
|
|
190
|
-
"content": content,
|
|
191
|
-
"agent_message": (pending or {}).get("agent_message")
|
|
192
|
-
or f"Updated {key.upper()} via doc chat.",
|
|
193
|
-
"created_at": (pending or {}).get("created_at"),
|
|
194
|
-
"base_hash": (pending or {}).get("base_hash"),
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
@router.post("/api/docs/{kind}/chat/discard")
|
|
198
|
-
async def discard_chat_patch(kind: str, request: Request):
|
|
199
|
-
doc_chat = request.app.state.doc_chat
|
|
200
|
-
key = _normalize_kind(kind)
|
|
201
|
-
repo_blocked = doc_chat.repo_blocked_reason()
|
|
202
|
-
if repo_blocked:
|
|
203
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
204
|
-
try:
|
|
205
|
-
async with doc_chat.doc_lock(key):
|
|
206
|
-
content = doc_chat.discard_patch(key)
|
|
207
|
-
except DocChatError as exc:
|
|
208
|
-
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
|
209
|
-
return {"status": "ok", "kind": key, "content": content}
|
|
210
|
-
|
|
211
|
-
@router.get("/api/docs/{kind}/chat/pending")
|
|
212
|
-
async def pending_chat_patch(kind: str, request: Request):
|
|
213
|
-
doc_chat = request.app.state.doc_chat
|
|
214
|
-
key = _normalize_kind(kind)
|
|
215
|
-
repo_blocked = doc_chat.repo_blocked_reason()
|
|
216
|
-
if repo_blocked:
|
|
217
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
218
|
-
pending = doc_chat.pending_patch(key)
|
|
219
|
-
if not pending:
|
|
220
|
-
raise HTTPException(status_code=404, detail="No pending patch")
|
|
221
|
-
return pending
|
|
222
|
-
|
|
223
|
-
@router.post("/api/ingest-spec", response_model=IngestSpecResponse)
|
|
224
|
-
async def ingest_spec(
|
|
225
|
-
request: Request, payload: Optional[IngestSpecRequest] = None
|
|
226
|
-
):
|
|
227
|
-
engine = request.app.state.engine
|
|
228
|
-
repo_blocked = engine.repo_busy_reason()
|
|
229
|
-
if repo_blocked:
|
|
230
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
231
|
-
spec_ingest = request.app.state.spec_ingest
|
|
232
|
-
force = False
|
|
233
|
-
spec_override: Optional[Path] = None
|
|
234
|
-
message: Optional[str] = None
|
|
235
|
-
agent: Optional[str] = None
|
|
236
|
-
model: Optional[str] = None
|
|
237
|
-
reasoning: Optional[str] = None
|
|
238
|
-
if payload:
|
|
239
|
-
force = payload.force
|
|
240
|
-
if payload.spec_path:
|
|
241
|
-
spec_override = Path(str(payload.spec_path))
|
|
242
|
-
message = payload.message
|
|
243
|
-
agent = payload.agent
|
|
244
|
-
model = payload.model
|
|
245
|
-
reasoning = payload.reasoning
|
|
246
|
-
try:
|
|
247
|
-
docs = await spec_ingest.execute(
|
|
248
|
-
force=force,
|
|
249
|
-
spec_path=spec_override,
|
|
250
|
-
message=message,
|
|
251
|
-
agent=agent,
|
|
252
|
-
model=model,
|
|
253
|
-
reasoning=reasoning,
|
|
254
|
-
)
|
|
255
|
-
except SpecIngestError as exc:
|
|
256
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
257
|
-
return docs
|
|
258
|
-
|
|
259
|
-
@router.post("/api/ingest-spec/interrupt", response_model=IngestSpecResponse)
|
|
260
|
-
async def ingest_spec_interrupt(request: Request):
|
|
261
|
-
spec_ingest = request.app.state.spec_ingest
|
|
262
|
-
try:
|
|
263
|
-
docs = await spec_ingest.interrupt()
|
|
264
|
-
except SpecIngestError as exc:
|
|
265
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
266
|
-
return docs
|
|
267
|
-
|
|
268
|
-
@router.get("/api/ingest-spec/pending", response_model=IngestSpecResponse)
|
|
269
|
-
def ingest_spec_pending(request: Request):
|
|
270
|
-
engine = request.app.state.engine
|
|
271
|
-
repo_blocked = engine.repo_busy_reason()
|
|
272
|
-
if repo_blocked:
|
|
273
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
274
|
-
spec_ingest = request.app.state.spec_ingest
|
|
275
|
-
try:
|
|
276
|
-
pending = spec_ingest.pending_patch()
|
|
277
|
-
if not pending:
|
|
278
|
-
raise HTTPException(
|
|
279
|
-
status_code=404, detail="No pending spec ingest patch"
|
|
280
|
-
)
|
|
281
|
-
return pending
|
|
282
|
-
except SpecIngestError as exc:
|
|
283
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
284
|
-
|
|
285
|
-
@router.post("/api/ingest-spec/apply", response_model=IngestSpecResponse)
|
|
286
|
-
def ingest_spec_apply(request: Request):
|
|
287
|
-
engine = request.app.state.engine
|
|
288
|
-
repo_blocked = engine.repo_busy_reason()
|
|
289
|
-
if repo_blocked:
|
|
290
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
291
|
-
spec_ingest = request.app.state.spec_ingest
|
|
292
|
-
try:
|
|
293
|
-
return spec_ingest.apply_patch()
|
|
294
|
-
except SpecIngestError as exc:
|
|
295
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
296
|
-
|
|
297
|
-
@router.post("/api/ingest-spec/discard", response_model=IngestSpecResponse)
|
|
298
|
-
def ingest_spec_discard(request: Request):
|
|
299
|
-
engine = request.app.state.engine
|
|
300
|
-
repo_blocked = engine.repo_busy_reason()
|
|
301
|
-
if repo_blocked:
|
|
302
|
-
raise HTTPException(status_code=409, detail=repo_blocked)
|
|
303
|
-
spec_ingest = request.app.state.spec_ingest
|
|
304
|
-
try:
|
|
305
|
-
return spec_ingest.discard_patch()
|
|
306
|
-
except SpecIngestError as exc:
|
|
307
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
308
|
-
|
|
309
|
-
@router.post("/api/docs/clear", response_model=DocsResponse)
|
|
310
|
-
def clear_docs(request: Request):
|
|
311
|
-
engine = request.app.state.engine
|
|
312
|
-
try:
|
|
313
|
-
docs = clear_work_docs(engine)
|
|
314
|
-
docs["spec"] = engine.docs.read_doc("spec")
|
|
315
|
-
docs["summary"] = engine.docs.read_doc("summary")
|
|
316
|
-
except Exception as exc:
|
|
317
|
-
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
|
318
|
-
return docs
|
|
319
|
-
|
|
320
|
-
@router.get("/api/usage", response_model=RepoUsageResponse)
|
|
321
|
-
def get_usage(
|
|
322
|
-
request: Request, since: Optional[str] = None, until: Optional[str] = None
|
|
323
|
-
):
|
|
324
|
-
engine = request.app.state.engine
|
|
325
|
-
try:
|
|
326
|
-
since_dt = parse_iso_datetime(since)
|
|
327
|
-
until_dt = parse_iso_datetime(until)
|
|
328
|
-
except UsageError as exc:
|
|
329
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
330
|
-
summary, status = get_repo_usage_summary_cached(
|
|
331
|
-
engine.repo_root,
|
|
332
|
-
default_codex_home(),
|
|
333
|
-
since=since_dt,
|
|
334
|
-
until=until_dt,
|
|
335
|
-
)
|
|
336
|
-
return {
|
|
337
|
-
"mode": "repo",
|
|
338
|
-
"repo": str(engine.repo_root),
|
|
339
|
-
"codex_home": str(default_codex_home()),
|
|
340
|
-
"since": since,
|
|
341
|
-
"until": until,
|
|
342
|
-
"status": status,
|
|
343
|
-
**summary.to_dict(),
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
@router.get("/api/usage/series", response_model=UsageSeriesResponse)
|
|
347
|
-
def get_usage_series(
|
|
348
|
-
request: Request,
|
|
349
|
-
since: Optional[str] = None,
|
|
350
|
-
until: Optional[str] = None,
|
|
351
|
-
bucket: str = "day",
|
|
352
|
-
segment: str = "none",
|
|
353
|
-
):
|
|
354
|
-
engine = request.app.state.engine
|
|
355
|
-
try:
|
|
356
|
-
since_dt = parse_iso_datetime(since)
|
|
357
|
-
until_dt = parse_iso_datetime(until)
|
|
358
|
-
except UsageError as exc:
|
|
359
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
360
|
-
try:
|
|
361
|
-
series, status = get_repo_usage_series_cached(
|
|
362
|
-
engine.repo_root,
|
|
363
|
-
default_codex_home(),
|
|
364
|
-
since=since_dt,
|
|
365
|
-
until=until_dt,
|
|
366
|
-
bucket=bucket,
|
|
367
|
-
segment=segment,
|
|
368
|
-
)
|
|
369
|
-
except UsageError as exc:
|
|
370
|
-
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
371
|
-
return {
|
|
372
|
-
"mode": "repo",
|
|
373
|
-
"repo": str(engine.repo_root),
|
|
374
|
-
"codex_home": str(default_codex_home()),
|
|
375
|
-
"since": since,
|
|
376
|
-
"until": until,
|
|
377
|
-
"status": status,
|
|
378
|
-
**series,
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return router
|