devops-bot-sdk 1.7.20__tar.gz → 1.7.33__tar.gz

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 (290) hide show
  1. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/PKG-INFO +3 -1
  2. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/PKG-INFO +3 -1
  3. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/SOURCES.txt +8 -0
  4. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/requires.txt +3 -0
  5. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/pyproject.toml +6 -0
  6. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/__init__.py +2 -2
  7. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agentd.py +35 -12
  8. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/schedules.py +56 -0
  9. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/cli.py +14 -9
  10. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/config.py +3 -0
  11. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/git_ops.py +73 -14
  12. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/graph_recon.py +4 -1
  13. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/graphify.py +17 -3
  14. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/helpdesk_kb.md +12 -1
  15. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ipc/handlers.py +106 -16
  16. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/log_colors.py +20 -0
  17. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/run_auto.py +48 -3
  18. devops_bot_sdk-1.7.33/sdk/schedule_timeline.py +171 -0
  19. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ticket_pools.py +88 -6
  20. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/api.py +18 -2
  21. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/dashboard.py +34 -9
  22. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/models.py +2 -0
  23. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/agents.html +1 -0
  24. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/app.js +896 -109
  25. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/chat.html +1 -0
  26. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/custom-agents.html +1 -0
  27. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/default-agents.html +1 -0
  28. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/faqs.html +1 -0
  29. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/help.html +6 -5
  30. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/index.html +1 -0
  31. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/report.html +1 -0
  32. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/runs.html +2 -1
  33. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/schedules.html +34 -13
  34. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/setup.html +1 -0
  35. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/styles.css +303 -4
  36. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/static/tickets.html +100 -26
  37. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_run_ticket.py +62 -0
  38. devops_bot_sdk-1.7.33/tests/test_graph_off_by_default.py +27 -0
  39. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_graph_recon.py +6 -0
  40. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_graphify_build.py +6 -0
  41. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_graphify_hook_install.py +6 -0
  42. devops_bot_sdk-1.7.33/tests/test_pool_pr_modes.py +143 -0
  43. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_prd_artifact.py +6 -0
  44. devops_bot_sdk-1.7.33/tests/test_quiet_run_log.py +40 -0
  45. devops_bot_sdk-1.7.33/tests/test_schedule_timeline.py +115 -0
  46. devops_bot_sdk-1.7.33/tests/test_theme_switch.py +35 -0
  47. devops_bot_sdk-1.7.33/tests/test_ticket_detail_view.py +51 -0
  48. devops_bot_sdk-1.7.33/tests/test_ui_no_native_dialogs.py +18 -0
  49. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/README.md +0 -0
  50. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  51. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  52. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  53. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/__init__.py +0 -0
  54. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/classifier.py +0 -0
  55. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/collectors/__init__.py +0 -0
  56. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/collectors/common.py +0 -0
  57. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/collectors/linux_auditd.py +0 -0
  58. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/collectors/macos_eslogger.py +0 -0
  59. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/collectors/windows_eventlog.py +0 -0
  60. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/models.py +0 -0
  61. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/os_setup.py +0 -0
  62. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/recorder.py +0 -0
  63. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/redact.py +0 -0
  64. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/settings.py +0 -0
  65. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/shipper.py +0 -0
  66. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/activity/spool.py +0 -0
  67. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agent_sharing.py +0 -0
  68. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/__init__.py +0 -0
  69. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/activity.py +0 -0
  70. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/builder.py +0 -0
  71. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/chat.py +0 -0
  72. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/connectors.py +0 -0
  73. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/__init__.py +0 -0
  74. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/claude_code.py +0 -0
  75. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/http.py +0 -0
  76. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/mcp.py +0 -0
  77. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/n8n.py +0 -0
  78. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/engines/shell.py +0 -0
  79. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/integrations.py +0 -0
  80. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/inventory.py +0 -0
  81. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/library/__init__.py +0 -0
  82. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/manifest.py +0 -0
  83. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/prompt_studio.py +0 -0
  84. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/prompt_template.py +0 -0
  85. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/prompt_vars.py +0 -0
  86. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/run_log.py +0 -0
  87. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/secrets.py +0 -0
  88. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/ticket_run.py +0 -0
  89. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/usage.py +0 -0
  90. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/agents/varstore.py +0 -0
  91. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/browser_profile.py +0 -0
  92. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/claude_usage.py +0 -0
  93. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/client.py +0 -0
  94. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/collectors/__init__.py +0 -0
  95. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/collectors/files.py +0 -0
  96. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/collectors/process.py +0 -0
  97. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/collectors/screenshot.py +0 -0
  98. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/crucial.py +0 -0
  99. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/custom_agents.py +0 -0
  100. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/deferred_tickets.py +0 -0
  101. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/departments.py +0 -0
  102. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/__init__.py +0 -0
  103. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/assets.py +0 -0
  104. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/bootstrap.py +0 -0
  105. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/browser.py +0 -0
  106. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/compare.py +0 -0
  107. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/design_verify/loop.py +0 -0
  108. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/estimator.py +0 -0
  109. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/exceptions.py +0 -0
  110. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/fallback_handoff.py +0 -0
  111. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/faqs.py +0 -0
  112. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/firewall.py +0 -0
  113. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/formats.py +0 -0
  114. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/github_fetch.py +0 -0
  115. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/github_ingest.py +0 -0
  116. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/help_actions.py +0 -0
  117. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/helpdesk.py +0 -0
  118. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/hooks/__init__.py +0 -0
  119. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/hooks/crucial_guard.py +0 -0
  120. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/instructions_template.py +0 -0
  121. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/intake.py +0 -0
  122. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ipc/__init__.py +0 -0
  123. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ipc/electron_bridge.py +0 -0
  124. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/journal.py +0 -0
  125. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/local_exec.py +0 -0
  126. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/memory_guard.py +0 -0
  127. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/model_policy.py +0 -0
  128. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/models/__init__.py +0 -0
  129. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/models/envelope.py +0 -0
  130. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/models/requests.py +0 -0
  131. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/models/responses.py +0 -0
  132. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/models/snapshots.py +0 -0
  133. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/phase_timer.py +0 -0
  134. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/plan_run.py +0 -0
  135. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/platform_compat.py +0 -0
  136. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/prd_progress.py +0 -0
  137. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/proof_readers.py +0 -0
  138. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/providers.py +0 -0
  139. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/py.typed +0 -0
  140. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/resume.py +0 -0
  141. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/router.py +0 -0
  142. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/schedule_tickets.py +0 -0
  143. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/scheduler.py +0 -0
  144. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/scope_plan.py +0 -0
  145. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/self_report.py +0 -0
  146. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/self_report_local.py +0 -0
  147. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/sse.py +0 -0
  148. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/swagger.py +0 -0
  149. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/task_file.py +0 -0
  150. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/task_types.py +0 -0
  151. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/test.py +0 -0
  152. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/test_pipeline.py +0 -0
  153. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ticket_board.py +0 -0
  154. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ticket_bulk.py +0 -0
  155. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ticket_fields.py +0 -0
  156. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ticket_plan.py +0 -0
  157. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/tickets.py +0 -0
  158. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/tiers/__init__.py +0 -0
  159. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/tiers/mini_agent.py +0 -0
  160. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/__init__.py +0 -0
  161. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/health.py +0 -0
  162. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/ip_allowlist.py +0 -0
  163. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/jobs.py +0 -0
  164. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/runner.py +0 -0
  165. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/security.py +0 -0
  166. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/server.py +0 -0
  167. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/service.py +0 -0
  168. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/session.py +0 -0
  169. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/setup_manager.py +0 -0
  170. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/ui/swagger.py +0 -0
  171. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/updater.py +0 -0
  172. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/url_access.py +0 -0
  173. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/vps_health.py +0 -0
  174. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/vps_identity.py +0 -0
  175. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/sdk/write_hook.py +0 -0
  176. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/setup.cfg +0 -0
  177. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_claude_runs.py +0 -0
  178. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_collectors.py +0 -0
  179. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_core.py +0 -0
  180. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_live_tracking.py +0 -0
  181. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_macos.py +0 -0
  182. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_os_setup.py +0 -0
  183. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_activity_pipeline.py +0 -0
  184. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_activity.py +0 -0
  185. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_activity_tracking.py +0 -0
  186. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_chat_features.py +0 -0
  187. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_crud_cli.py +0 -0
  188. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_listing.py +0 -0
  189. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_prompt_async.py +0 -0
  190. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_prompt_models.py +0 -0
  191. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_schedules.py +0 -0
  192. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_sharing.py +0 -0
  193. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agent_workspace_settings.py +0 -0
  194. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_agents_connectors_builder.py +0 -0
  195. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_allowed_tools_config.py +0 -0
  196. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_approval_park.py +0 -0
  197. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_auto_agent_dispatch.py +0 -0
  198. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_auto_ticket_queue.py +0 -0
  199. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_browser_profile.py +0 -0
  200. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_cheap_tier.py +0 -0
  201. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_claude_usage_gate.py +0 -0
  202. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_client_jira_projects.py +0 -0
  203. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_config_token_diagnostics.py +0 -0
  204. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_configure_token_owner.py +0 -0
  205. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_console_encoding.py +0 -0
  206. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_crash_recovery.py +0 -0
  207. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_create_safe_retry.py +0 -0
  208. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_deferred_tickets.py +0 -0
  209. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_departments.py +0 -0
  210. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_done_transition.py +0 -0
  211. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_epic_decompose_run.py +0 -0
  212. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_epic_inherited_agent_id.py +0 -0
  213. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_epic_session_isolation.py +0 -0
  214. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_estimator.py +0 -0
  215. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_fallback_cli.py +0 -0
  216. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_fallback_cli_upgrade.py +0 -0
  217. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_faqs.py +0 -0
  218. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_firewall_open_on_update.py +0 -0
  219. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_formats.py +0 -0
  220. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_git_action.py +0 -0
  221. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_github_fetch.py +0 -0
  222. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_github_ingest.py +0 -0
  223. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_health.py +0 -0
  224. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_help_actions.py +0 -0
  225. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_help_attachments.py +0 -0
  226. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_help_questions.py +0 -0
  227. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_helpdesk.py +0 -0
  228. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_infographic_data.py +0 -0
  229. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_instructions_template.py +0 -0
  230. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_intake_job_outcome.py +0 -0
  231. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_intake_plan_review.py +0 -0
  232. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_journal.py +0 -0
  233. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_limit_fallback_handoff.py +0 -0
  234. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_local_exec_provider.py +0 -0
  235. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_log_colors_backlog.py +0 -0
  236. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_mcp_route_contract.py +0 -0
  237. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_memory_guard.py +0 -0
  238. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_model_policy.py +0 -0
  239. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_panel_help.py +0 -0
  240. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_panel_ticket_schedules.py +0 -0
  241. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_parallel_tickets.py +0 -0
  242. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_phase_timer.py +0 -0
  243. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_plan_new_command.py +0 -0
  244. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_plan_run_activity.py +0 -0
  245. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_pr_identity.py +0 -0
  246. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_project_path_resolution.py +0 -0
  247. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_proof_readers.py +0 -0
  248. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_providers.py +0 -0
  249. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_recon_session_isolation.py +0 -0
  250. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_resume.py +0 -0
  251. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_router.py +0 -0
  252. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_run_auto_agent_only.py +0 -0
  253. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_run_outputs.py +0 -0
  254. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_run_verdict_is_honest.py +0 -0
  255. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_schedule_api.py +0 -0
  256. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_schedule_outputs_and_plans.py +0 -0
  257. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_schedule_tickets.py +0 -0
  258. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_scheduler.py +0 -0
  259. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_scheduler_transient_retry.py +0 -0
  260. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_self_report.py +0 -0
  261. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_service_token_warning.py +0 -0
  262. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_stale_panel_restart.py +0 -0
  263. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_swagger_command.py +0 -0
  264. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_task_file_and_plan_run.py +0 -0
  265. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_task_file_format_doc.py +0 -0
  266. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_board.py +0 -0
  267. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_bulk.py +0 -0
  268. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_cli.py +0 -0
  269. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_fields.py +0 -0
  270. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_plan.py +0 -0
  271. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_pools.py +0 -0
  272. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_run_resolve_by_id.py +0 -0
  273. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_schedule_and_agent.py +0 -0
  274. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ticket_speed_fixes.py +0 -0
  275. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_tier_flag_parity.py +0 -0
  276. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ui_gate.py +0 -0
  277. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_ui_lifespan.py +0 -0
  278. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_update_timer.py +0 -0
  279. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_updater_extras.py +0 -0
  280. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_updater_ignores_cwd.py +0 -0
  281. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_updater_pep668.py +0 -0
  282. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_updater_reports_the_truth.py +0 -0
  283. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_url_access.py +0 -0
  284. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_vps_health.py +0 -0
  285. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_vps_only_reporting.py +0 -0
  286. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_windows_loop_identity.py +0 -0
  287. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_windows_panel_task.py +0 -0
  288. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_windows_stop_and_pidfile.py +0 -0
  289. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_windows_task_paths.py +0 -0
  290. {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.33}/tests/test_write_hook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.7.20
3
+ Version: 1.7.33
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -22,6 +22,8 @@ Requires-Dist: fastapi>=0.110; extra == "ui"
22
22
  Requires-Dist: uvicorn>=0.29; extra == "ui"
23
23
  Requires-Dist: psutil>=5.9; extra == "ui"
24
24
  Requires-Dist: python-multipart>=0.0.9; extra == "ui"
25
+ Provides-Extra: ui-e2e
26
+ Requires-Dist: playwright>=1.45; extra == "ui-e2e"
25
27
  Provides-Extra: all
26
28
  Requires-Dist: Pillow>=10.0; extra == "all"
27
29
  Requires-Dist: psutil>=5.9; extra == "all"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.7.20
3
+ Version: 1.7.33
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -22,6 +22,8 @@ Requires-Dist: fastapi>=0.110; extra == "ui"
22
22
  Requires-Dist: uvicorn>=0.29; extra == "ui"
23
23
  Requires-Dist: psutil>=5.9; extra == "ui"
24
24
  Requires-Dist: python-multipart>=0.0.9; extra == "ui"
25
+ Provides-Extra: ui-e2e
26
+ Requires-Dist: playwright>=1.45; extra == "ui-e2e"
25
27
  Provides-Extra: all
26
28
  Requires-Dist: Pillow>=10.0; extra == "all"
27
29
  Requires-Dist: psutil>=5.9; extra == "all"
@@ -50,6 +50,7 @@ sdk/resume.py
50
50
  sdk/router.py
51
51
  sdk/run_auto.py
52
52
  sdk/schedule_tickets.py
53
+ sdk/schedule_timeline.py
53
54
  sdk/scheduler.py
54
55
  sdk/scope_plan.py
55
56
  sdk/self_report.py
@@ -206,6 +207,7 @@ tests/test_formats.py
206
207
  tests/test_git_action.py
207
208
  tests/test_github_fetch.py
208
209
  tests/test_github_ingest.py
210
+ tests/test_graph_off_by_default.py
209
211
  tests/test_graph_recon.py
210
212
  tests/test_graphify_build.py
211
213
  tests/test_graphify_hook_install.py
@@ -231,11 +233,13 @@ tests/test_parallel_tickets.py
231
233
  tests/test_phase_timer.py
232
234
  tests/test_plan_new_command.py
233
235
  tests/test_plan_run_activity.py
236
+ tests/test_pool_pr_modes.py
234
237
  tests/test_pr_identity.py
235
238
  tests/test_prd_artifact.py
236
239
  tests/test_project_path_resolution.py
237
240
  tests/test_proof_readers.py
238
241
  tests/test_providers.py
242
+ tests/test_quiet_run_log.py
239
243
  tests/test_recon_session_isolation.py
240
244
  tests/test_resume.py
241
245
  tests/test_router.py
@@ -245,6 +249,7 @@ tests/test_run_verdict_is_honest.py
245
249
  tests/test_schedule_api.py
246
250
  tests/test_schedule_outputs_and_plans.py
247
251
  tests/test_schedule_tickets.py
252
+ tests/test_schedule_timeline.py
248
253
  tests/test_scheduler.py
249
254
  tests/test_scheduler_transient_retry.py
250
255
  tests/test_self_report.py
@@ -253,9 +258,11 @@ tests/test_stale_panel_restart.py
253
258
  tests/test_swagger_command.py
254
259
  tests/test_task_file_and_plan_run.py
255
260
  tests/test_task_file_format_doc.py
261
+ tests/test_theme_switch.py
256
262
  tests/test_ticket_board.py
257
263
  tests/test_ticket_bulk.py
258
264
  tests/test_ticket_cli.py
265
+ tests/test_ticket_detail_view.py
259
266
  tests/test_ticket_fields.py
260
267
  tests/test_ticket_plan.py
261
268
  tests/test_ticket_pools.py
@@ -265,6 +272,7 @@ tests/test_ticket_speed_fixes.py
265
272
  tests/test_tier_flag_parity.py
266
273
  tests/test_ui_gate.py
267
274
  tests/test_ui_lifespan.py
275
+ tests/test_ui_no_native_dialogs.py
268
276
  tests/test_update_timer.py
269
277
  tests/test_updater_extras.py
270
278
  tests/test_updater_ignores_cwd.py
@@ -22,3 +22,6 @@ fastapi>=0.110
22
22
  uvicorn>=0.29
23
23
  psutil>=5.9
24
24
  python-multipart>=0.0.9
25
+
26
+ [ui-e2e]
27
+ playwright>=1.45
@@ -41,6 +41,9 @@ ui = [
41
41
  # raises at request time without it, so it belongs in [ui]
42
42
  # alongside fastapi rather than in an optional extra.
43
43
  ]
44
+ ui-e2e = [
45
+ "playwright>=1.45", # tests/ui_e2e — headless-Chromium panel tests (then: python -m playwright install chromium)
46
+ ]
44
47
  all = [
45
48
  "Pillow>=10.0",
46
49
  "psutil>=5.9",
@@ -60,6 +63,9 @@ agentos-swagger = "sdk.swagger:main" # where /docs is + can you reach it
60
63
  Homepage = "https://agentos.io"
61
64
  Repository = "https://github.com/consultancy-outfit/DevOpsBot-SDK"
62
65
 
66
+ [tool.pytest.ini_options]
67
+ markers = ["ui_e2e: headless-Chromium control-panel tests (need the ui-e2e extra; skipped without it)"]
68
+
63
69
  [tool.setuptools.dynamic]
64
70
  version = { attr = "sdk.__version__" } # bump sdk/__init__.py → wheel + client + server all follow
65
71
 
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.7.20
3
+ Version: 1.7.33
4
4
 
5
5
  Public surface:
6
6
  BackendClient.from_config() — create client from ~/.agentos/config.toml
@@ -34,7 +34,7 @@ Rules:
34
34
  - All data egress through submit_webhook only
35
35
  """
36
36
 
37
- __version__ = "1.7.20" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
37
+ __version__ = "1.7.33" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
38
38
  __author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
39
39
 
40
40
  from sdk.client import BackendClient
@@ -359,21 +359,41 @@ async def _dispatch_agent_run(
359
359
  manifest.integrations, available, env=secret_env,
360
360
  )
361
361
 
362
- # EPHEMERAL variables: filled FRESH from the ticket (when one is attached) and/or
363
- # from explicit run-time values — never persisted. Explicit ``extra_variables``
364
- # win over ticket-derived ones. With neither, unresolved {{vars}} are left for
365
- # the agent to ask about or default, exactly as before.
366
- resolved_prompt = manifest.prompt
362
+ # {{variables}}, most specific first: explicit run-time values (UI/API/CLI) win
363
+ # over the attached ticket's fields, which win over the values last saved for
364
+ # this agent (sdk/agents/varstore.py — what the panel's Run used). Nothing here
365
+ # is persisted. A person-started run (auto_approve) that would still leave a
366
+ # placeholder unfilled is REFUSED up front: the agent cannot do the work, so it
367
+ # would only spend a run asking for the values (ticket-instructions-writer,
368
+ # 2026-10-27, got literal {{ticket_key}} / {{repos_root}}).
369
+ from sdk.agents import varstore as agent_varstore
370
+
367
371
  names = extract_variables(manifest.prompt)
368
- if names and (task or extra_variables):
369
- values = values_from_ticket(names, task) if task else {}
372
+ used_inputs: dict[str, str] = {}
373
+ if names:
374
+ saved = {k: v for k, v in agent_varstore.load_vars(manifest.name).items()
375
+ if k in names and str(v).strip()}
376
+ values = dict(saved)
377
+ if task:
378
+ values.update({k: v for k, v in values_from_ticket(names, task).items() if str(v).strip()})
370
379
  if extra_variables:
371
- values = {**values, **{k: str(v) for k, v in extra_variables.items() if str(v).strip()}}
380
+ values.update({k: str(v) for k, v in extra_variables.items() if str(v).strip()})
372
381
  resolved_prompt, missing = substitute_variables(manifest.prompt, values)
373
- if values:
382
+ used_inputs = {k: v for k, v in values.items() if k in names}
383
+ if missing and auto_approve:
384
+ outcome["status"] = "missing_inputs"
385
+ outcome["missing"] = missing
386
+ outcome["error"] = (
387
+ f"'{manifest.name}' needs {', '.join(missing)} — fill "
388
+ f"{'it' if len(missing) == 1 else 'them'} in, or pick a ticket that has "
389
+ f"{'it' if len(missing) == 1 else 'them'}. Nothing was run."
390
+ )
391
+ logger.info("agentd.missing_inputs agent=%s missing=%s", manifest.name, missing)
392
+ return outcome
393
+ if used_inputs:
374
394
  logger.info(
375
- "agentd.vars_filled agent=%s filled=%s missing=%s",
376
- manifest.name, sorted(values), sorted(missing),
395
+ "agentd.vars_filled agent=%s filled=%s from_saved=%s missing=%s",
396
+ manifest.name, sorted(used_inputs), sorted(saved), sorted(missing),
377
397
  )
378
398
  manifest = manifest.model_copy(update={"prompt": resolved_prompt})
379
399
 
@@ -455,9 +475,12 @@ async def _dispatch_agent_run(
455
475
  from sdk.agents.engines import claude_code as claude_code_engine
456
476
  from sdk.agents import run_log
457
477
 
458
- _kind = "ticket" if task else "scheduled"
478
+ # A person pressed Run (auto_approve) → "run"; only an unattended
479
+ # trigger without a ticket is "scheduled".
480
+ _kind = "ticket" if task else ("run" if auto_approve else "scheduled")
459
481
  _log_path = run_log.start_run(
460
482
  manifest.name, scope="custom", engine=manifest.engine, kind=_kind,
483
+ variables=used_inputs or None,
461
484
  )
462
485
  run_log.log_line(_log_path, f"task_id={task_id}")
463
486
 
@@ -411,6 +411,7 @@ def mark_result(schedule_id: str, *, ok: bool, status: str = "",
411
411
  if schedule is None:
412
412
  return None
413
413
  schedule["last_status"] = status or ("ok" if ok else "failed")
414
+ _append_history(schedule, ok=ok, output_file=output_file)
414
415
  if output_file:
415
416
  schedule["last_output_file"] = output_file
416
417
  if delivered_to:
@@ -431,6 +432,61 @@ def mark_result(schedule_id: str, *, ok: bool, status: str = "",
431
432
  return schedule
432
433
 
433
434
 
435
+ # Every outcome mark_result records, one JSON line each, so the Schedules page can
436
+ # show what ran before the latest run. Not ``*.json``: list_schedules globs those.
437
+ HISTORY_NAME = "history.jsonl"
438
+ HISTORY_MAX_LINES = 5000
439
+
440
+
441
+ def history_path() -> Path:
442
+ return SCHEDULES_DIR / HISTORY_NAME
443
+
444
+
445
+ def _append_history(schedule: dict, *, ok: bool, output_file: str = "") -> None:
446
+ """Best-effort: a history failure never affects the run or the schedule."""
447
+ row = {
448
+ "at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
449
+ "fired_at": schedule.get("last_fire_at") or "",
450
+ "schedule_id": schedule.get("schedule_id") or "",
451
+ "agent": schedule.get("agent") or "",
452
+ "kind": schedule.get("kind") or "agent",
453
+ "ok": bool(ok),
454
+ "status": schedule.get("last_status") or "",
455
+ "output_file": output_file or "",
456
+ }
457
+ try:
458
+ path = history_path()
459
+ path.parent.mkdir(parents=True, exist_ok=True)
460
+ with path.open("a", encoding="utf-8") as fh:
461
+ fh.write(json.dumps(row, ensure_ascii=False) + "\n")
462
+ if path.stat().st_size > HISTORY_MAX_LINES * 400: # trim rarely, keep the newest
463
+ lines = path.read_text(encoding="utf-8").splitlines()[-HISTORY_MAX_LINES:]
464
+ path.write_text("\n".join(lines) + "\n", encoding="utf-8")
465
+ except OSError as exc:
466
+ logger.debug("schedules.history_write_failed err=%s", exc)
467
+
468
+
469
+ def read_history(since: datetime | None = None) -> list[dict]:
470
+ """Recorded outcomes, oldest first (optionally only those at/after ``since``)."""
471
+ out: list[dict] = []
472
+ try:
473
+ lines = history_path().read_text(encoding="utf-8").splitlines()
474
+ except OSError:
475
+ return out
476
+ for line in lines:
477
+ try:
478
+ row = json.loads(line)
479
+ except ValueError:
480
+ continue
481
+ if not isinstance(row, dict):
482
+ continue
483
+ at = _parse_iso(row.get("fired_at")) or _parse_iso(row.get("at"))
484
+ if at is None or (since is not None and at < since):
485
+ continue
486
+ out.append(row)
487
+ return out
488
+
489
+
434
490
  def for_agent(agent: str) -> list[dict]:
435
491
  return [s for s in list_schedules() if s.get("agent") == agent]
436
492
 
@@ -1264,12 +1264,12 @@ _POOL_USAGE = """usage: agentos pool <command> — up to 50 tickets you run to
1264
1264
 
1265
1265
  agentos pool list # every pool, its size and last run
1266
1266
  agentos pool show NAME # run order, each ticket's summary/status, instructions
1267
- agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] # new pool (keys in run order)
1267
+ agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] [--pr-mode per_ticket|stacked|single] # new pool (keys in run order)
1268
1268
  agentos pool add NAME KEY… [--at POS] # add tickets (at the end, or at position POS)
1269
1269
  agentos pool remove NAME KEY… # take tickets out
1270
1270
  agentos pool move NAME KEY POS # move one ticket to position POS (1 = first)
1271
1271
  agentos pool order NAME KEY… # these first, in this order; the rest follow
1272
- agentos pool set NAME [--instructions TEXT | --clear-instructions] [--parallel N] [--rename NEW]
1272
+ agentos pool set NAME [--instructions TEXT | --clear-instructions] [--parallel N] [--pr-mode MODE] [--rename NEW]
1273
1273
  agentos pool run NAME [--parallel N] # run it now (= agentos-auto pool NAME)
1274
1274
  agentos pool delete NAME # remove the pool (tickets are untouched)
1275
1275
 
@@ -1306,8 +1306,11 @@ def _pool_opts(args: list[str], valued: tuple[str, ...], bare: tuple[str, ...] =
1306
1306
 
1307
1307
  def _pool_print(pool: dict, info: dict | None = None) -> None:
1308
1308
  from sdk import log_colors
1309
+ from sdk.ticket_pools import PR_MODE_LABELS as TP_LABELS
1309
1310
  paint = log_colors.colorize if log_colors.enabled() else (lambda x: x)
1310
- print(f"pool {pool['name']} — {len(pool['keys'])} ticket(s), up to {pool.get('parallel')} at once"
1311
+ mode = pool.get("pr_mode") or "per_ticket"
1312
+ at_once = f"up to {pool.get('parallel')} at once" if mode == "per_ticket" else "one at a time"
1313
+ print(f"pool {pool['name']} — {len(pool['keys'])} ticket(s), {at_once}, {TP_LABELS.get(mode, mode)}"
1311
1314
  + (f", last run {pool['last_run_at']}" if pool.get("last_run_at") else ""))
1312
1315
  width = max(len(k) for k in pool["keys"]) if pool["keys"] else 0
1313
1316
  for n, k in enumerate(pool["keys"], 1):
@@ -1358,11 +1361,13 @@ def _pool_command(args: list[str]) -> None:
1358
1361
  _pool_print(pool, info)
1359
1362
  return
1360
1363
  if sub == "create":
1361
- pos, opts = _pool_opts(rest, ("--instructions", "--parallel"))
1364
+ pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--pr-mode"))
1362
1365
  if len(pos) < 2:
1363
- print("usage: agentos pool create NAME KEY… [--instructions TEXT] [--parallel N]")
1366
+ print("usage: agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] "
1367
+ "[--pr-mode per_ticket|stacked|single]")
1364
1368
  sys.exit(1)
1365
- pool = TP.create(pos[0], pos[1:], opts.get("--instructions", ""), _parallel(opts))
1369
+ pool = TP.create(pos[0], pos[1:], opts.get("--instructions", ""), _parallel(opts),
1370
+ opts.get("--pr-mode"))
1366
1371
  shown = f'"{pool["name"]}"' if " " in pool["name"] else pool["name"]
1367
1372
  print(f"✓ created pool {pool['name']} with {len(pool['keys'])} ticket(s) — "
1368
1373
  f"run it: agentos pool run {shown}")
@@ -1389,15 +1394,15 @@ def _pool_command(args: list[str]) -> None:
1389
1394
  sys.exit(1)
1390
1395
  pool = TP.order(rest[0], rest[1:])
1391
1396
  elif sub == "set":
1392
- pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--rename"),
1397
+ pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--rename", "--pr-mode"),
1393
1398
  ("--clear-instructions",))
1394
1399
  if len(pos) != 1 or not opts:
1395
1400
  print("usage: agentos pool set NAME [--instructions TEXT | --clear-instructions] "
1396
- "[--parallel N] [--rename NEW]")
1401
+ "[--parallel N] [--pr-mode per_ticket|stacked|single] [--rename NEW]")
1397
1402
  sys.exit(1)
1398
1403
  instr = "" if opts.get("--clear-instructions") else opts.get("--instructions")
1399
1404
  pool = TP.update(pos[0], instructions=instr, parallel=_parallel(opts),
1400
- rename=opts.get("--rename"))
1405
+ rename=opts.get("--rename"), pr_mode=opts.get("--pr-mode"))
1401
1406
  elif sub == "delete":
1402
1407
  if not rest:
1403
1408
  print("usage: agentos pool delete NAME")
@@ -407,6 +407,9 @@ FLAG_TIERED_ROUTING = "AGENTOS_TIERED_ROUTING"
407
407
  FLAG_JOURNAL = "AGENTOS_JOURNAL"
408
408
  #: Write the generated PRD to ``docs/prd/<KEY>.md`` in the repo.
409
409
  FLAG_PRD_FILE = "AGENTOS_PRD_FILE"
410
+ #: The knowledge graph (graphify + graph recon). OFF by default since 1.7.27;
411
+ #: ``AGENTOS_GRAPHIFY=1`` (env or config.toml) turns it back on.
412
+ FLAG_GRAPHIFY = "AGENTOS_GRAPHIFY"
410
413
  #: Supervise ``graphify watch`` instead of relying on the debounce.
411
414
  FLAG_GRAPH_WATCH = "AGENTOS_GRAPHIFY_WATCH"
412
415
  #: Cheap-tier mini agent (sdk/tiers/). Requires backend reachability.
@@ -80,9 +80,9 @@ _TICKET_BRANCH_RE = re.compile(r"^[A-Za-z][A-Za-z0-9]{1,9}-\d+$")
80
80
 
81
81
 
82
82
  def _is_work_branch(name: str) -> bool:
83
- """True when `name` is one of OUR generated work branches (feature/* or a
84
- bare ticket id) — i.e. never a legitimate base."""
85
- return name.startswith("feature/") or bool(_TICKET_BRANCH_RE.match(name))
83
+ """True when `name` is one of OUR generated work branches (feature/*, a pool's
84
+ pool/* or a bare ticket id) — i.e. never a legitimate base."""
85
+ return name.startswith(("feature/", "pool/")) or bool(_TICKET_BRANCH_RE.match(name))
86
86
 
87
87
 
88
88
  async def detect_default_branch(path: str, env: dict) -> str:
@@ -163,9 +163,16 @@ async def start_branch(
163
163
  github_token: str | None,
164
164
  base: str | None = None,
165
165
  branch_name: str | None = None,
166
+ continue_branch: bool = False,
166
167
  ) -> dict | None:
167
168
  """Create + check out a feature branch off the resolved base.
168
169
 
170
+ ``continue_branch`` (a one-PR ticket pool, after its first ticket): check out
171
+ the EXISTING ``branch_name`` as it stands — local, else ``origin/`` — and bring
172
+ it up to date, instead of re-cutting it from ``base``; ``base`` is returned
173
+ unchanged so the PR keeps its target. Re-cutting would throw away the earlier
174
+ tickets' commits.
175
+
169
176
  Branch name:
170
177
  - `branch_name` given (an explicit name parsed from the Jira
171
178
  humanInstructions or a configured template, e.g. the exact ticket id
@@ -196,6 +203,17 @@ async def start_branch(
196
203
  return None
197
204
 
198
205
  explicit_name = (branch_name or "").strip().lstrip("/")
206
+ if continue_branch and explicit_name:
207
+ await _run(["git", "fetch", "origin"], path, env, timeout=180.0)
208
+ rc, _, _ = await _run(["git", "checkout", explicit_name], path, env)
209
+ if rc != 0:
210
+ rc, _, _ = await _run(["git", "checkout", "-B", explicit_name, f"origin/{explicit_name}"], path, env)
211
+ if rc == 0:
212
+ await _run(["git", "pull", "--ff-only", "origin", explicit_name], path, env, timeout=120.0)
213
+ pr_base = (base or "").strip() or await detect_default_branch(path, env)
214
+ logger.info("git_ops.branch | %s continued (pool), PR base %s", explicit_name, pr_base)
215
+ return {"branch": explicit_name, "base": pr_base}
216
+ # Not there yet (the pool's first ticket): cut it like any named branch.
199
217
  if explicit_name:
200
218
  # Honour the exact name the human/convention asked for (e.g. "CD-72").
201
219
  branch = explicit_name
@@ -212,15 +230,20 @@ async def start_branch(
212
230
  # local ref of that name, then to a bare branch, if the remote lacks it.
213
231
  await _run(["git", "fetch", "origin", explicit], path, env, timeout=120.0)
214
232
  resolved = "main" if explicit == branch else explicit
215
- rc, _, _ = await _run(["git", "checkout", "-B", branch, f"origin/{resolved}"], path, env)
216
- if rc != 0:
217
- rc, _, _ = await _run(["git", "checkout", "-B", branch, resolved], path, env)
218
- if rc != 0:
233
+ refs = [r for r in (f"origin/{resolved}", resolved) if await _ref_exists(path, env, r)]
234
+ if not refs:
235
+ # The base does not exist anywhere (a typo, or a brand-new repo): cut
236
+ # from HEAD, and say which branch that really is.
219
237
  rc, _, _ = await _run(["git", "checkout", "-B", branch], path, env)
220
- if rc != 0:
238
+ if rc != 0:
239
+ return None
240
+ logger.warning("git_ops.branch | base %s not found — %s cut from the current checkout", resolved, branch)
241
+ return {"branch": branch, "base": resolved, "note": f"base {resolved} not found — cut from the current checkout"}
242
+ info = await _checkout_from(path, env, branch, refs)
243
+ if info is None:
221
244
  return None
222
245
  logger.info("git_ops.branch | %s ← explicit base %s", branch, resolved)
223
- return {"branch": branch, "base": resolved}
246
+ return {"branch": branch, "base": resolved, **info}
224
247
 
225
248
  # Default: base = the CURRENT checked-out branch (the user's working branch).
226
249
  rc, cur, _ = await _run(["git", "rev-parse", "--abbrev-ref", "HEAD"], path, env)
@@ -238,13 +261,49 @@ async def start_branch(
238
261
  resolved = await detect_default_branch(path, env)
239
262
  if resolved == branch:
240
263
  resolved = "main"
241
- rc, _, _ = await _run(["git", "checkout", "-B", branch, f"origin/{resolved}"], path, env)
242
- if rc != 0:
243
- rc, _, _ = await _run(["git", "checkout", "-B", branch], path, env)
244
- if rc != 0:
264
+ refs = [r for r in (f"origin/{resolved}", resolved) if await _ref_exists(path, env, r)]
265
+ info = await _checkout_from(path, env, branch, refs) if refs else None
266
+ if info is None:
267
+ # Never fall back to the stale work branch that is checked out: that is
268
+ # how one ticket's half-finished changes end up in the next one's PR.
269
+ logger.warning("git_ops.branch | %s: could not cut from %s (HEAD was %r)", branch, resolved, cur or "detached")
245
270
  return None
246
271
  logger.info("git_ops.branch | %s ← default base %s (HEAD was %r)", branch, resolved, cur or "detached")
247
- return {"branch": branch, "base": resolved}
272
+ return {"branch": branch, "base": resolved, **info}
273
+
274
+
275
+ async def _ref_exists(path: str, env: dict, ref: str) -> bool:
276
+ rc, _, _ = await _run(["git", "rev-parse", "--verify", "--quiet", ref + "^{commit}"], path, env)
277
+ return rc == 0
278
+
279
+
280
+ async def _checkout_from(path: str, env: dict, branch: str, refs: list[str]) -> dict | None:
281
+ """Check ``branch`` out fresh from the first of ``refs`` that works → {} or
282
+ {"stashed": msg}; None when none does.
283
+
284
+ The usual reason a checkout fails is uncommitted changes in the way —
285
+ typically a previous ticket's half-finished work. Those are STASHED (kept, with
286
+ a message naming this branch; ``git stash list`` shows them) and the checkout
287
+ retried, instead of quietly cutting the branch from whatever is checked out —
288
+ which would carry those changes, and a stale codebase, into this ticket's PR.
289
+ """
290
+ for ref in refs:
291
+ rc, _, _ = await _run(["git", "checkout", "-B", branch, ref], path, env)
292
+ if rc == 0:
293
+ return {}
294
+ if not await has_local_changes(path):
295
+ return None
296
+ msg = f"agentos: uncommitted changes set aside before {branch}"
297
+ rc, _, err = await _run(["git", "stash", "push", "--include-untracked", "-m", msg], path, env)
298
+ if rc != 0:
299
+ logger.warning("git_ops.stash_failed %s: %s", branch, err[:200])
300
+ return None
301
+ logger.warning("git_ops.branch | stashed uncommitted changes before %s", branch)
302
+ for ref in refs:
303
+ rc, _, _ = await _run(["git", "checkout", "-B", branch, ref], path, env)
304
+ if rc == 0:
305
+ return {"stashed": msg}
306
+ return None
248
307
 
249
308
 
250
309
  async def _remote_owner_repo(path: str, env: dict) -> tuple[str, str] | None:
@@ -75,7 +75,10 @@ _CAMEL_RE = re.compile(r"[A-Z]+(?![a-z])|[A-Z][a-z0-9]*|[a-z0-9]+")
75
75
 
76
76
 
77
77
  def _disabled() -> bool:
78
- return bool(os.getenv("AGENTOS_NO_GRAPH_RECON"))
78
+ if os.getenv("AGENTOS_NO_GRAPH_RECON"):
79
+ return True
80
+ from sdk import graphify # no graph (off by default) → no graph recon
81
+ return not graphify.enabled()
79
82
 
80
83
 
81
84
  def _split_identifier(word: str) -> list[str]:
@@ -6,8 +6,11 @@ hook**, so the agent queries the graph instead of loading whole files — keepin
6
6
  large projects inside the context window.
7
7
 
8
8
  Everything here is best-effort and never raises: if graphify is unavailable or a
9
- step fails, the run continues on plain `claude`. Disable with
10
- ``AGENTOS_NO_GRAPHIFY=1``.
9
+ step fails, the run continues on plain `claude`.
10
+
11
+ OFF by default (1.7.27): nothing is installed, built or queried unless
12
+ ``AGENTOS_GRAPHIFY=1`` is set (environment or ``config.toml``). The code stays so
13
+ it can be switched back on; ``AGENTOS_NO_GRAPHIFY=1`` still forces it off.
11
14
 
12
15
  Per-project flow (called once before each local `claude` run):
13
16
  ensure_installed() → auto-install `graphifyy` via uv → pipx → pip if missing
@@ -45,8 +48,19 @@ _SKILL_MARKER = _AGENTOS_DIR / ".graphify_skill_installed"
45
48
  _STATE_FILE = _AGENTOS_DIR / "graphify_state.json"
46
49
 
47
50
 
51
+ def enabled() -> bool:
52
+ """True only when switched on (``AGENTOS_GRAPHIFY=1``) and not forced off."""
53
+ if os.getenv("AGENTOS_NO_GRAPHIFY"):
54
+ return False
55
+ try:
56
+ from sdk import config
57
+ return config.flag(config.FLAG_GRAPHIFY)
58
+ except Exception: # noqa: BLE001 — a config hiccup leaves it off
59
+ return False
60
+
61
+
48
62
  def _disabled() -> bool:
49
- return bool(os.getenv("AGENTOS_NO_GRAPHIFY"))
63
+ return not enabled()
50
64
 
51
65
 
52
66
  def is_available() -> bool:
@@ -170,7 +170,12 @@ never overwritten (this VPS: after-night-scans.conf, 03:30 UTC). Opt out `AGENTO
170
170
  development|content|research|design|general`); only development mentions git. Generate
171
171
  with AI: `agentos ticket gen-instructions KEY… [--kind K]`, or the ✨ button under any
172
172
  instructions box on the panel.
173
- - Panel: Tickets page → Ticket pools, **Add to pool**, **Bulk update…** (shows current values), **Bulk create from plan**. Help page: FAQs (sdk/faqs.py).
173
+ - Run log (agentos-auto logs, panel Run & Logs): while the agent works it shows each file it edits (✎) and one progress line a minute (⋯ working 3m · 24 steps …), not every tool call — every step stays in the ticket's claude log, and AGENTOS_VERBOSE_STEPS=1 brings per-step lines back. A ticket quiet for 2+ minutes (e.g. a long test run) gets "… still working on KEY — quiet for Nm". Colours: ticket start bold cyan, edits cyan, branch blue, PR link bold green, model/RAM/internal lines dim.
174
+ - Running an agent with {{inputs}} (panel Run / Run on a ticket, `agentos agent run`): each input comes from the form, else the picked ticket, else the value saved from the agent's last run. If one is still missing, the run is refused before it starts — "Not run — fill in ticket_key, repos_root" — instead of spending a run that only asks for them. Run logs say "Kind: run" for a run a person started and list its inputs; "scheduled" is only an unattended trigger.
175
+ - Knowledge graph (graphify + graph recon) is OFF by default since 1.7.27: tickets use the AI recon pass, prompts don't mention graphify, and the Runs page hides its Knowledge graph box. Turn it back on with `AGENTOS_GRAPHIFY=1` (environment, `.env`, or `graphify = true` in ~/.agentos/config.toml); `AGENTOS_NO_GRAPHIFY=1` still forces it off.
176
+ - A ticket's branch always starts from its real base: if a previous run's uncommitted changes are in the way they are stashed (`agentos: uncommitted changes set aside before <branch>` — `git stash list`, `git stash pop` to restore) and the run log says so; if the base still cannot be checked out, no branch is cut.
177
+ - Pool PRs (`--pr-mode`, panel: pool editor → Pull requests): **per_ticket** (default) = each ticket its own branch + PR; **stacked** = each ticket branches from the previous ticket's branch in the same repo and its PR targets that branch (ticket N builds on N-1; merge them in order); **single** = every ticket commits to `pool/<name>` and the pool gets ONE PR into the usual base. stacked and single run the tickets one at a time in pool order; a ticket that changed nothing leaves the stack where it was.
178
+ - Panel: Tickets page has tabs **Tickets · Board · Pools**. Move tickets Jira-style: tick them and press **Move to ▾**, change **Status** in the side panel, or drag a card between columns on the **Board** (each card also has a ⋯ move menu). Lists are paged (12 per page; ticks survive paging). Schedules page has tabs **Timeline · Schedules · New schedule · Run history** — Timeline shows what already ran (result + ticket, Output opens the run) and what runs next, for 12 h / 24 h / 3 days / 7 days. Help: Enter asks, Shift+Enter = new line. Tickets list: each row shows the description preview, type, priority, points and assignee; **click a row** to open the whole ticket in a side panel (properties, full description, Human Instructions, Run / Edit / Copy / Delete; ↑↓ or j/k move between tickets, Esc closes). Also Ticket pools, **Add to pool**, **Bulk update…** (shows current values), **Bulk create from plan**. FAQs page in the sidebar (sdk/faqs.py). Light / System / Dark switch at the bottom of the sidebar (remembered per browser; System follows the computer).
174
179
 
175
180
  ## Known issues and their fixes
176
181
 
@@ -276,6 +281,12 @@ admin** = a zip of the case's diagnostics, errors and logs (no SDK source). API:
276
281
  `GET /api/ui/help/case/{name}/bundle` (`sdk/ui/api.py`). It runs on the machine the
277
282
  panel runs on, so it reads that machine's logs.
278
283
 
284
+ Panel dialogs: the panel never uses the browser's `confirm()` / `prompt()` any more.
285
+ Delete / replace / run / bulk-update / **Generate with AI** / **Insert template** ask in
286
+ an in-page dialog — **Esc** or **Cancel** closes it and nothing is sent; Tab stays inside
287
+ it. "I pressed Esc and nothing happened" is therefore the dialog being cancelled, not a
288
+ bug. The Tickets **Add N to pool ▾** menu is keyboard-operable (↑ ↓, Enter, Esc).
289
+
279
290
  ## Useful commands (all verified to exist)
280
291
 
281
292
  ```