codex-autorunner 1.0.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.
Files changed (227) hide show
  1. codex_autorunner/__init__.py +12 -1
  2. codex_autorunner/agents/codex/harness.py +1 -1
  3. codex_autorunner/agents/opencode/client.py +113 -4
  4. codex_autorunner/agents/opencode/constants.py +3 -0
  5. codex_autorunner/agents/opencode/harness.py +6 -1
  6. codex_autorunner/agents/opencode/runtime.py +59 -18
  7. codex_autorunner/agents/opencode/supervisor.py +4 -0
  8. codex_autorunner/agents/registry.py +36 -7
  9. codex_autorunner/bootstrap.py +226 -4
  10. codex_autorunner/cli.py +5 -1174
  11. codex_autorunner/codex_cli.py +20 -84
  12. codex_autorunner/core/__init__.py +20 -0
  13. codex_autorunner/core/about_car.py +119 -1
  14. codex_autorunner/core/app_server_ids.py +59 -0
  15. codex_autorunner/core/app_server_threads.py +17 -2
  16. codex_autorunner/core/app_server_utils.py +165 -0
  17. codex_autorunner/core/archive.py +349 -0
  18. codex_autorunner/core/codex_runner.py +6 -2
  19. codex_autorunner/core/config.py +433 -4
  20. codex_autorunner/core/context_awareness.py +38 -0
  21. codex_autorunner/core/docs.py +0 -122
  22. codex_autorunner/core/drafts.py +58 -4
  23. codex_autorunner/core/exceptions.py +4 -0
  24. codex_autorunner/core/filebox.py +265 -0
  25. codex_autorunner/core/flows/controller.py +96 -2
  26. codex_autorunner/core/flows/models.py +13 -0
  27. codex_autorunner/core/flows/reasons.py +52 -0
  28. codex_autorunner/core/flows/reconciler.py +134 -0
  29. codex_autorunner/core/flows/runtime.py +57 -4
  30. codex_autorunner/core/flows/store.py +142 -7
  31. codex_autorunner/core/flows/transition.py +27 -15
  32. codex_autorunner/core/flows/ux_helpers.py +272 -0
  33. codex_autorunner/core/flows/worker_process.py +32 -6
  34. codex_autorunner/core/git_utils.py +62 -0
  35. codex_autorunner/core/hub.py +291 -20
  36. codex_autorunner/core/lifecycle_events.py +253 -0
  37. codex_autorunner/core/notifications.py +14 -2
  38. codex_autorunner/core/path_utils.py +2 -1
  39. codex_autorunner/core/pma_audit.py +224 -0
  40. codex_autorunner/core/pma_context.py +496 -0
  41. codex_autorunner/core/pma_dispatch_interceptor.py +284 -0
  42. codex_autorunner/core/pma_lifecycle.py +527 -0
  43. codex_autorunner/core/pma_queue.py +367 -0
  44. codex_autorunner/core/pma_safety.py +221 -0
  45. codex_autorunner/core/pma_state.py +115 -0
  46. codex_autorunner/core/ports/__init__.py +28 -0
  47. codex_autorunner/{integrations/agents → core/ports}/agent_backend.py +13 -8
  48. codex_autorunner/core/ports/backend_orchestrator.py +41 -0
  49. codex_autorunner/{integrations/agents → core/ports}/run_event.py +23 -6
  50. codex_autorunner/core/prompt.py +0 -80
  51. codex_autorunner/core/prompts.py +56 -172
  52. codex_autorunner/core/redaction.py +0 -4
  53. codex_autorunner/core/review_context.py +11 -9
  54. codex_autorunner/core/runner_controller.py +35 -33
  55. codex_autorunner/core/runner_state.py +147 -0
  56. codex_autorunner/core/runtime.py +829 -0
  57. codex_autorunner/core/sqlite_utils.py +13 -4
  58. codex_autorunner/core/state.py +7 -10
  59. codex_autorunner/core/state_roots.py +62 -0
  60. codex_autorunner/core/supervisor_protocol.py +15 -0
  61. codex_autorunner/core/templates/__init__.py +39 -0
  62. codex_autorunner/core/templates/git_mirror.py +234 -0
  63. codex_autorunner/core/templates/provenance.py +56 -0
  64. codex_autorunner/core/templates/scan_cache.py +120 -0
  65. codex_autorunner/core/text_delta_coalescer.py +54 -0
  66. codex_autorunner/core/ticket_linter_cli.py +218 -0
  67. codex_autorunner/core/ticket_manager_cli.py +494 -0
  68. codex_autorunner/core/time_utils.py +11 -0
  69. codex_autorunner/core/types.py +18 -0
  70. codex_autorunner/core/update.py +4 -5
  71. codex_autorunner/core/update_paths.py +28 -0
  72. codex_autorunner/core/usage.py +164 -12
  73. codex_autorunner/core/utils.py +125 -15
  74. codex_autorunner/flows/review/__init__.py +17 -0
  75. codex_autorunner/{core/review.py → flows/review/service.py} +37 -34
  76. codex_autorunner/flows/ticket_flow/definition.py +52 -3
  77. codex_autorunner/integrations/agents/__init__.py +11 -19
  78. codex_autorunner/integrations/agents/backend_orchestrator.py +302 -0
  79. codex_autorunner/integrations/agents/codex_adapter.py +90 -0
  80. codex_autorunner/integrations/agents/codex_backend.py +177 -25
  81. codex_autorunner/integrations/agents/opencode_adapter.py +108 -0
  82. codex_autorunner/integrations/agents/opencode_backend.py +305 -32
  83. codex_autorunner/integrations/agents/runner.py +86 -0
  84. codex_autorunner/integrations/agents/wiring.py +279 -0
  85. codex_autorunner/integrations/app_server/client.py +7 -60
  86. codex_autorunner/integrations/app_server/env.py +2 -107
  87. codex_autorunner/{core/app_server_events.py → integrations/app_server/event_buffer.py} +15 -8
  88. codex_autorunner/integrations/telegram/adapter.py +65 -0
  89. codex_autorunner/integrations/telegram/config.py +46 -0
  90. codex_autorunner/integrations/telegram/constants.py +1 -1
  91. codex_autorunner/integrations/telegram/doctor.py +228 -6
  92. codex_autorunner/integrations/telegram/handlers/callbacks.py +7 -0
  93. codex_autorunner/integrations/telegram/handlers/commands/execution.py +236 -74
  94. codex_autorunner/integrations/telegram/handlers/commands/files.py +314 -75
  95. codex_autorunner/integrations/telegram/handlers/commands/flows.py +1496 -71
  96. codex_autorunner/integrations/telegram/handlers/commands/workspace.py +498 -37
  97. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +206 -48
  98. codex_autorunner/integrations/telegram/handlers/commands_spec.py +20 -3
  99. codex_autorunner/integrations/telegram/handlers/messages.py +27 -1
  100. codex_autorunner/integrations/telegram/handlers/selections.py +61 -1
  101. codex_autorunner/integrations/telegram/helpers.py +22 -1
  102. codex_autorunner/integrations/telegram/runtime.py +9 -4
  103. codex_autorunner/integrations/telegram/service.py +45 -10
  104. codex_autorunner/integrations/telegram/state.py +38 -0
  105. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +338 -43
  106. codex_autorunner/integrations/telegram/transport.py +13 -4
  107. codex_autorunner/integrations/templates/__init__.py +27 -0
  108. codex_autorunner/integrations/templates/scan_agent.py +312 -0
  109. codex_autorunner/routes/__init__.py +37 -76
  110. codex_autorunner/routes/agents.py +2 -137
  111. codex_autorunner/routes/analytics.py +2 -238
  112. codex_autorunner/routes/app_server.py +2 -131
  113. codex_autorunner/routes/base.py +2 -596
  114. codex_autorunner/routes/file_chat.py +4 -833
  115. codex_autorunner/routes/flows.py +4 -977
  116. codex_autorunner/routes/messages.py +4 -456
  117. codex_autorunner/routes/repos.py +2 -196
  118. codex_autorunner/routes/review.py +2 -147
  119. codex_autorunner/routes/sessions.py +2 -175
  120. codex_autorunner/routes/settings.py +2 -168
  121. codex_autorunner/routes/shared.py +2 -275
  122. codex_autorunner/routes/system.py +4 -193
  123. codex_autorunner/routes/usage.py +2 -86
  124. codex_autorunner/routes/voice.py +2 -119
  125. codex_autorunner/routes/workspace.py +2 -270
  126. codex_autorunner/server.py +4 -4
  127. codex_autorunner/static/agentControls.js +61 -16
  128. codex_autorunner/static/app.js +126 -14
  129. codex_autorunner/static/archive.js +826 -0
  130. codex_autorunner/static/archiveApi.js +37 -0
  131. codex_autorunner/static/autoRefresh.js +7 -7
  132. codex_autorunner/static/chatUploads.js +137 -0
  133. codex_autorunner/static/dashboard.js +224 -171
  134. codex_autorunner/static/docChatCore.js +185 -13
  135. codex_autorunner/static/fileChat.js +68 -40
  136. codex_autorunner/static/fileboxUi.js +159 -0
  137. codex_autorunner/static/hub.js +114 -131
  138. codex_autorunner/static/index.html +375 -49
  139. codex_autorunner/static/messages.js +568 -87
  140. codex_autorunner/static/notifications.js +255 -0
  141. codex_autorunner/static/pma.js +1167 -0
  142. codex_autorunner/static/preserve.js +17 -0
  143. codex_autorunner/static/settings.js +128 -6
  144. codex_autorunner/static/smartRefresh.js +52 -0
  145. codex_autorunner/static/streamUtils.js +57 -0
  146. codex_autorunner/static/styles.css +9798 -6143
  147. codex_autorunner/static/tabs.js +152 -11
  148. codex_autorunner/static/templateReposSettings.js +225 -0
  149. codex_autorunner/static/terminal.js +18 -0
  150. codex_autorunner/static/ticketChatActions.js +165 -3
  151. codex_autorunner/static/ticketChatStream.js +17 -119
  152. codex_autorunner/static/ticketEditor.js +137 -15
  153. codex_autorunner/static/ticketTemplates.js +798 -0
  154. codex_autorunner/static/tickets.js +821 -98
  155. codex_autorunner/static/turnEvents.js +27 -0
  156. codex_autorunner/static/turnResume.js +33 -0
  157. codex_autorunner/static/utils.js +39 -0
  158. codex_autorunner/static/workspace.js +389 -82
  159. codex_autorunner/static/workspaceFileBrowser.js +15 -13
  160. codex_autorunner/surfaces/__init__.py +5 -0
  161. codex_autorunner/surfaces/cli/__init__.py +6 -0
  162. codex_autorunner/surfaces/cli/cli.py +2534 -0
  163. codex_autorunner/surfaces/cli/codex_cli.py +20 -0
  164. codex_autorunner/surfaces/cli/pma_cli.py +817 -0
  165. codex_autorunner/surfaces/telegram/__init__.py +3 -0
  166. codex_autorunner/surfaces/web/__init__.py +1 -0
  167. codex_autorunner/surfaces/web/app.py +2223 -0
  168. codex_autorunner/surfaces/web/hub_jobs.py +192 -0
  169. codex_autorunner/surfaces/web/middleware.py +587 -0
  170. codex_autorunner/surfaces/web/pty_session.py +370 -0
  171. codex_autorunner/surfaces/web/review.py +6 -0
  172. codex_autorunner/surfaces/web/routes/__init__.py +82 -0
  173. codex_autorunner/surfaces/web/routes/agents.py +138 -0
  174. codex_autorunner/surfaces/web/routes/analytics.py +284 -0
  175. codex_autorunner/surfaces/web/routes/app_server.py +132 -0
  176. codex_autorunner/surfaces/web/routes/archive.py +357 -0
  177. codex_autorunner/surfaces/web/routes/base.py +615 -0
  178. codex_autorunner/surfaces/web/routes/file_chat.py +1117 -0
  179. codex_autorunner/surfaces/web/routes/filebox.py +227 -0
  180. codex_autorunner/surfaces/web/routes/flows.py +1354 -0
  181. codex_autorunner/surfaces/web/routes/messages.py +490 -0
  182. codex_autorunner/surfaces/web/routes/pma.py +1652 -0
  183. codex_autorunner/surfaces/web/routes/repos.py +197 -0
  184. codex_autorunner/surfaces/web/routes/review.py +148 -0
  185. codex_autorunner/surfaces/web/routes/sessions.py +176 -0
  186. codex_autorunner/surfaces/web/routes/settings.py +169 -0
  187. codex_autorunner/surfaces/web/routes/shared.py +277 -0
  188. codex_autorunner/surfaces/web/routes/system.py +196 -0
  189. codex_autorunner/surfaces/web/routes/templates.py +634 -0
  190. codex_autorunner/surfaces/web/routes/usage.py +89 -0
  191. codex_autorunner/surfaces/web/routes/voice.py +120 -0
  192. codex_autorunner/surfaces/web/routes/workspace.py +271 -0
  193. codex_autorunner/surfaces/web/runner_manager.py +25 -0
  194. codex_autorunner/surfaces/web/schemas.py +469 -0
  195. codex_autorunner/surfaces/web/static_assets.py +490 -0
  196. codex_autorunner/surfaces/web/static_refresh.py +86 -0
  197. codex_autorunner/surfaces/web/terminal_sessions.py +78 -0
  198. codex_autorunner/tickets/__init__.py +8 -1
  199. codex_autorunner/tickets/agent_pool.py +53 -4
  200. codex_autorunner/tickets/files.py +37 -16
  201. codex_autorunner/tickets/lint.py +50 -0
  202. codex_autorunner/tickets/models.py +6 -1
  203. codex_autorunner/tickets/outbox.py +50 -2
  204. codex_autorunner/tickets/runner.py +396 -57
  205. codex_autorunner/web/__init__.py +5 -1
  206. codex_autorunner/web/app.py +2 -1949
  207. codex_autorunner/web/hub_jobs.py +2 -191
  208. codex_autorunner/web/middleware.py +2 -586
  209. codex_autorunner/web/pty_session.py +2 -369
  210. codex_autorunner/web/runner_manager.py +2 -24
  211. codex_autorunner/web/schemas.py +2 -376
  212. codex_autorunner/web/static_assets.py +4 -441
  213. codex_autorunner/web/static_refresh.py +2 -85
  214. codex_autorunner/web/terminal_sessions.py +2 -77
  215. codex_autorunner/workspace/paths.py +49 -33
  216. codex_autorunner-1.2.0.dist-info/METADATA +150 -0
  217. codex_autorunner-1.2.0.dist-info/RECORD +339 -0
  218. codex_autorunner/core/adapter_utils.py +0 -21
  219. codex_autorunner/core/engine.py +0 -2653
  220. codex_autorunner/core/static_assets.py +0 -55
  221. codex_autorunner-1.0.0.dist-info/METADATA +0 -246
  222. codex_autorunner-1.0.0.dist-info/RECORD +0 -251
  223. /codex_autorunner/{routes → surfaces/web/routes}/terminal_images.py +0 -0
  224. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.2.0.dist-info}/WHEEL +0 -0
  225. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.2.0.dist-info}/entry_points.txt +0 -0
  226. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.2.0.dist-info}/licenses/LICENSE +0 -0
  227. {codex_autorunner-1.0.0.dist-info → codex_autorunner-1.2.0.dist-info}/top_level.txt +0 -0
@@ -9,6 +9,7 @@ from datetime import datetime, timedelta, timezone
9
9
  from pathlib import Path
10
10
  from typing import Any, Callable, Iterable, Optional, Sequence
11
11
 
12
+ from ...core.state_roots import resolve_global_state_root
12
13
  from ...core.utils import (
13
14
  RepoNotFoundError,
14
15
  canonicalize_path,
@@ -885,10 +886,13 @@ def _format_help_text(command_specs: dict[str, CommandSpec]) -> str:
885
886
  "new",
886
887
  "resume",
887
888
  "review",
889
+ "flow",
890
+ "reply",
888
891
  "pr",
889
892
  "agent",
890
893
  "model",
891
894
  "approvals",
895
+ "pma",
892
896
  "status",
893
897
  "diff",
894
898
  "mention",
@@ -917,6 +921,23 @@ def _format_help_text(command_specs: dict[str, CommandSpec]) -> str:
917
921
  lines.append("/review custom <instructions> (or /review custom to prompt)")
918
922
  lines.append("/review detached ...")
919
923
 
924
+ if "flow" in command_specs:
925
+ lines.append("")
926
+ lines.append("Flow:")
927
+ lines.append("/flow")
928
+ lines.append("/flow status [run_id]")
929
+ lines.append("/flow bootstrap [--force-new]")
930
+ lines.append("/flow issue <issue#|url>")
931
+ lines.append("/flow plan <text>")
932
+ lines.append("/flow resume [run_id]")
933
+ lines.append("/flow stop [run_id]")
934
+ lines.append("/flow recover [run_id]")
935
+ lines.append("/flow restart")
936
+ lines.append("/flow archive [run_id] [--force]")
937
+ lines.append("/flow reply <message>")
938
+ if "reply" in command_specs:
939
+ lines.append("/reply <message> (legacy)")
940
+
920
941
  lines.append("")
921
942
  lines.append("Other:")
922
943
  lines.append("Note: /resume is supported for the codex and opencode agents.")
@@ -2103,7 +2124,7 @@ def _telegram_lock_path(token: str) -> Path:
2103
2124
  if not isinstance(token, str) or not token:
2104
2125
  raise ValueError("token is required")
2105
2126
  digest = hashlib.sha256(token.encode("utf-8")).hexdigest()[:12]
2106
- return Path.home() / ".codex-autorunner" / "locks" / f"telegram_bot_{digest}.lock"
2127
+ return resolve_global_state_root() / "locks" / f"telegram_bot_{digest}.lock"
2107
2128
 
2108
2129
 
2109
2130
  def _read_lock_payload(path: Path) -> Optional[dict[str, Any]]:
@@ -265,8 +265,11 @@ class TelegramRuntimeHelpers:
265
265
  text = f"{prefix}{text}"
266
266
  return self._prepare_message(text)
267
267
 
268
- def _render_message(self, text: str) -> tuple[str, Optional[str]]:
269
- parse_mode = self._config.parse_mode
268
+ def _render_message(
269
+ self, text: str, *, parse_mode: Optional[str] = None
270
+ ) -> tuple[str, Optional[str]]:
271
+ # Allow callers to override parse_mode (needed for ad-hoc Markdown/HTML sends)
272
+ parse_mode = self._config.parse_mode if parse_mode is None else parse_mode
270
273
  if not parse_mode:
271
274
  return text, None
272
275
  if parse_mode == "HTML":
@@ -275,8 +278,10 @@ class TelegramRuntimeHelpers:
275
278
  return _format_telegram_markdown(text, parse_mode), parse_mode
276
279
  return text, parse_mode
277
280
 
278
- def _prepare_message(self, text: str) -> tuple[str, Optional[str]]:
279
- rendered, parse_mode = self._render_message(text)
281
+ def _prepare_message(
282
+ self, text: str, *, parse_mode: Optional[str] = None
283
+ ) -> tuple[str, Optional[str]]:
284
+ rendered, parse_mode = self._render_message(text, parse_mode=parse_mode)
280
285
  # Avoid parse_mode when chunking to keep markup intact.
281
286
  if parse_mode and len(rendered) <= TELEGRAM_MAX_MESSAGE_LENGTH:
282
287
  return rendered, parse_mode
@@ -16,11 +16,17 @@ if TYPE_CHECKING:
16
16
  from .state import TelegramTopicRecord
17
17
 
18
18
  from ...agents.opencode.supervisor import OpenCodeSupervisor
19
+ from ...core.app_server_threads import (
20
+ AppServerThreadRegistry,
21
+ default_app_server_threads_path,
22
+ )
19
23
  from ...core.flows.models import FlowRunRecord
24
+ from ...core.hub import HubSupervisor
20
25
  from ...core.locks import process_alive
21
26
  from ...core.logging_utils import log_event
22
27
  from ...core.request_context import reset_conversation_id, set_conversation_id
23
28
  from ...core.state import now_iso
29
+ from ...core.state_roots import resolve_global_state_root
24
30
  from ...core.text_delta_coalescer import TextDeltaCoalescer
25
31
  from ...core.utils import build_opencode_supervisor
26
32
  from ...housekeeping import HousekeepingConfig, run_housekeeping_for_roots
@@ -47,7 +53,6 @@ from .config import (
47
53
  )
48
54
  from .constants import (
49
55
  DEFAULT_INTERRUPT_TIMEOUT_SECONDS,
50
- DEFAULT_WORKSPACE_STATE_ROOT,
51
56
  QUEUED_PLACEHOLDER_TEXT,
52
57
  TurnKey,
53
58
  )
@@ -173,6 +178,31 @@ class TelegramBotService(
173
178
  self._logger = logger or logging.getLogger(__name__)
174
179
  self._hub_root = hub_root
175
180
  self._manifest_path = manifest_path
181
+ self._hub_supervisor = None
182
+ self._hub_thread_registry = None
183
+ if self._hub_root:
184
+ try:
185
+ self._hub_supervisor = HubSupervisor.from_path(self._hub_root)
186
+ except Exception as exc:
187
+ log_event(
188
+ self._logger,
189
+ logging.WARNING,
190
+ "telegram.pma.hub_supervisor.unavailable",
191
+ hub_root=str(self._hub_root),
192
+ exc=exc,
193
+ )
194
+ try:
195
+ self._hub_thread_registry = AppServerThreadRegistry(
196
+ default_app_server_threads_path(self._hub_root)
197
+ )
198
+ except Exception as exc:
199
+ log_event(
200
+ self._logger,
201
+ logging.WARNING,
202
+ "telegram.pma.thread_registry.unavailable",
203
+ hub_root=str(self._hub_root),
204
+ exc=exc,
205
+ )
176
206
  self._update_repo_url = update_repo_url
177
207
  self._update_repo_ref = update_repo_ref
178
208
  self._update_skip_checks = update_skip_checks
@@ -182,7 +212,7 @@ class TelegramBotService(
182
212
  config.state_file, default_approval_mode=config.defaults.approval_mode
183
213
  )
184
214
  self._router = TopicRouter(self._store)
185
- self._app_server_state_root = Path(DEFAULT_WORKSPACE_STATE_ROOT).expanduser()
215
+ self._app_server_state_root = resolve_global_state_root() / "workspaces"
186
216
  self._app_server_supervisor = WorkspaceAppServerSupervisor(
187
217
  config.app_server_command,
188
218
  state_root=self._app_server_state_root,
@@ -247,9 +277,16 @@ class TelegramBotService(
247
277
  store=self._store,
248
278
  pause_targets=self._ticket_flow_pause_targets,
249
279
  send_message_with_outbox=self._send_message_with_outbox,
280
+ send_document=self._send_document,
281
+ pause_config=self._config.pause_dispatch_notifications,
282
+ default_notification_chat_id=self._config.default_notification_chat_id,
283
+ hub_root=hub_root,
284
+ manifest_path=manifest_path,
285
+ config_root=self._config.root,
250
286
  )
251
287
  self._resume_options: dict[str, SelectionState] = {}
252
288
  self._bind_options: dict[str, SelectionState] = {}
289
+ self._flow_run_options: dict[str, SelectionState] = {}
253
290
  self._update_options: dict[str, SelectionState] = {}
254
291
  self._update_confirm_options: dict[str, bool] = {}
255
292
  self._review_commit_options: dict[str, ReviewCommitSelectionState] = {}
@@ -886,6 +923,8 @@ class TelegramBotService(
886
923
  self._resume_options.pop(key, None)
887
924
  elif cache_name == "bind_options":
888
925
  self._bind_options.pop(key, None)
926
+ elif cache_name == "flow_run_options":
927
+ self._flow_run_options.pop(key, None)
889
928
  elif cache_name == "agent_options":
890
929
  self._agent_options.pop(key, None)
891
930
  elif cache_name == "update_options":
@@ -938,6 +977,9 @@ class TelegramBotService(
938
977
  self._evict_expired_cache_entries(
939
978
  "bind_options", self._config.cache.selection_state_ttl_seconds
940
979
  )
980
+ self._evict_expired_cache_entries(
981
+ "flow_run_options", self._config.cache.selection_state_ttl_seconds
982
+ )
941
983
  self._evict_expired_cache_entries(
942
984
  "agent_options", self._config.cache.selection_state_ttl_seconds
943
985
  )
@@ -1027,7 +1069,7 @@ class TelegramBotService(
1027
1069
 
1028
1070
  def _load_ticket_flow_pause(
1029
1071
  self, workspace_root: Path
1030
- ) -> Optional[tuple[str, str, str]]:
1072
+ ) -> Optional[tuple[str, str, str, Optional[Path]]]:
1031
1073
  return self._ticket_flow_bridge._load_ticket_flow_pause(workspace_root)
1032
1074
 
1033
1075
  def _latest_dispatch_seq(self, history_dir: Path) -> Optional[str]:
@@ -1036,13 +1078,6 @@ class TelegramBotService(
1036
1078
  def _format_ticket_flow_pause_reason(self, record: "FlowRunRecord") -> str:
1037
1079
  return self._ticket_flow_bridge._format_ticket_flow_pause_reason(record)
1038
1080
 
1039
- def _format_ticket_flow_pause_message(
1040
- self, run_id: str, seq: str, content: str
1041
- ) -> str:
1042
- return self._ticket_flow_bridge._format_ticket_flow_pause_message(
1043
- run_id, seq, content
1044
- )
1045
-
1046
1081
  def _get_paused_ticket_flow(
1047
1082
  self, workspace_root: Path, preferred_run_id: Optional[str] = None
1048
1083
  ) -> Optional[tuple[str, FlowRunRecord]]:
@@ -190,6 +190,11 @@ class TelegramTopicRecord:
190
190
  repo_id: Optional[str] = None
191
191
  workspace_path: Optional[str] = None
192
192
  workspace_id: Optional[str] = None
193
+ pma_enabled: bool = False
194
+ pma_prev_repo_id: Optional[str] = None
195
+ pma_prev_workspace_path: Optional[str] = None
196
+ pma_prev_workspace_id: Optional[str] = None
197
+ pma_prev_active_thread_id: Optional[str] = None
193
198
  active_thread_id: Optional[str] = None
194
199
  thread_ids: list[str] = dataclasses.field(default_factory=list)
195
200
  thread_summaries: dict[str, ThreadSummary] = dataclasses.field(default_factory=dict)
@@ -220,6 +225,29 @@ class TelegramTopicRecord:
220
225
  workspace_id = payload.get("workspace_id") or payload.get("workspaceId")
221
226
  if not isinstance(workspace_id, str):
222
227
  workspace_id = None
228
+ pma_enabled = payload.get("pma_enabled") or payload.get("pmaEnabled")
229
+ if not isinstance(pma_enabled, bool):
230
+ pma_enabled = False
231
+ pma_prev_repo_id = payload.get("pma_prev_repo_id") or payload.get(
232
+ "pmaPrevRepoId"
233
+ )
234
+ if not isinstance(pma_prev_repo_id, str):
235
+ pma_prev_repo_id = None
236
+ pma_prev_workspace_path = payload.get("pma_prev_workspace_path") or payload.get(
237
+ "pmaPrevWorkspacePath"
238
+ )
239
+ if not isinstance(pma_prev_workspace_path, str):
240
+ pma_prev_workspace_path = None
241
+ pma_prev_workspace_id = payload.get("pma_prev_workspace_id") or payload.get(
242
+ "pmaPrevWorkspaceId"
243
+ )
244
+ if not isinstance(pma_prev_workspace_id, str):
245
+ pma_prev_workspace_id = None
246
+ pma_prev_active_thread_id = payload.get(
247
+ "pma_prev_active_thread_id"
248
+ ) or payload.get("pmaPrevActiveThreadId")
249
+ if not isinstance(pma_prev_active_thread_id, str):
250
+ pma_prev_active_thread_id = None
223
251
  active_thread_id = payload.get("active_thread_id") or payload.get(
224
252
  "activeThreadId"
225
253
  )
@@ -301,6 +329,11 @@ class TelegramTopicRecord:
301
329
  repo_id=repo_id,
302
330
  workspace_path=workspace_path,
303
331
  workspace_id=workspace_id,
332
+ pma_enabled=pma_enabled,
333
+ pma_prev_repo_id=pma_prev_repo_id,
334
+ pma_prev_workspace_path=pma_prev_workspace_path,
335
+ pma_prev_workspace_id=pma_prev_workspace_id,
336
+ pma_prev_active_thread_id=pma_prev_active_thread_id,
304
337
  active_thread_id=active_thread_id,
305
338
  thread_ids=thread_ids,
306
339
  thread_summaries=thread_summaries,
@@ -324,6 +357,11 @@ class TelegramTopicRecord:
324
357
  "repo_id": self.repo_id,
325
358
  "workspace_path": self.workspace_path,
326
359
  "workspace_id": self.workspace_id,
360
+ "pma_enabled": self.pma_enabled,
361
+ "pma_prev_repo_id": self.pma_prev_repo_id,
362
+ "pma_prev_workspace_path": self.pma_prev_workspace_path,
363
+ "pma_prev_workspace_id": self.pma_prev_workspace_id,
364
+ "pma_prev_active_thread_id": self.pma_prev_active_thread_id,
327
365
  "active_thread_id": self.active_thread_id,
328
366
  "thread_ids": list(self.thread_ids),
329
367
  "thread_summaries": {