devops-bot-sdk 1.7.47__tar.gz → 1.7.48__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 (305) hide show
  1. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/PKG-INFO +1 -1
  2. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
  3. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/SOURCES.txt +2 -0
  4. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/__init__.py +2 -2
  5. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agentd.py +6 -0
  6. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/cli.py +22 -1
  7. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_data/areas.json +9 -9
  8. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_data/commands.json +10 -0
  9. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_data/releases.json +10 -0
  10. devops_bot_sdk-1.7.48/sdk/help_data/snapshot.json +17 -0
  11. devops_bot_sdk-1.7.48/sdk/install_marker.py +175 -0
  12. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/run_auto.py +6 -0
  13. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/server.py +6 -0
  14. devops_bot_sdk-1.7.48/tests/test_install_marker.py +169 -0
  15. devops_bot_sdk-1.7.47/sdk/help_data/snapshot.json +0 -17
  16. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/README.md +0 -0
  17. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  18. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  19. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/requires.txt +0 -0
  20. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  21. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/pyproject.toml +0 -0
  22. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/__init__.py +0 -0
  23. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/classifier.py +0 -0
  24. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/collectors/__init__.py +0 -0
  25. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/collectors/common.py +0 -0
  26. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/collectors/linux_auditd.py +0 -0
  27. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/collectors/macos_eslogger.py +0 -0
  28. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/collectors/windows_eventlog.py +0 -0
  29. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/models.py +0 -0
  30. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/os_setup.py +0 -0
  31. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/recorder.py +0 -0
  32. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/redact.py +0 -0
  33. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/settings.py +0 -0
  34. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/shipper.py +0 -0
  35. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/activity/spool.py +0 -0
  36. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agent_sharing.py +0 -0
  37. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/__init__.py +0 -0
  38. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/activity.py +0 -0
  39. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/builder.py +0 -0
  40. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/chat.py +0 -0
  41. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/connectors.py +0 -0
  42. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/__init__.py +0 -0
  43. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/claude_code.py +0 -0
  44. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/http.py +0 -0
  45. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/mcp.py +0 -0
  46. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/n8n.py +0 -0
  47. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/engines/shell.py +0 -0
  48. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/integrations.py +0 -0
  49. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/inventory.py +0 -0
  50. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/library/__init__.py +0 -0
  51. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/manifest.py +0 -0
  52. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/prompt_studio.py +0 -0
  53. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/prompt_template.py +0 -0
  54. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/prompt_vars.py +0 -0
  55. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/run_log.py +0 -0
  56. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/schedules.py +0 -0
  57. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/secrets.py +0 -0
  58. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/ticket_run.py +0 -0
  59. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/usage.py +0 -0
  60. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/agents/varstore.py +0 -0
  61. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/browser_profile.py +0 -0
  62. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/claude_usage.py +0 -0
  63. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/client.py +0 -0
  64. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/collectors/__init__.py +0 -0
  65. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/collectors/files.py +0 -0
  66. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/collectors/process.py +0 -0
  67. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/collectors/screenshot.py +0 -0
  68. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/config.py +0 -0
  69. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/crucial.py +0 -0
  70. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/custom_agents.py +0 -0
  71. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/deferred_tickets.py +0 -0
  72. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/departments.py +0 -0
  73. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/__init__.py +0 -0
  74. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/assets.py +0 -0
  75. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/bootstrap.py +0 -0
  76. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/browser.py +0 -0
  77. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/compare.py +0 -0
  78. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/design_verify/loop.py +0 -0
  79. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/estimator.py +0 -0
  80. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/exceptions.py +0 -0
  81. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/fallback_handoff.py +0 -0
  82. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/faqs.py +0 -0
  83. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/firewall.py +0 -0
  84. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/formats.py +0 -0
  85. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/git_ops.py +0 -0
  86. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/github_fetch.py +0 -0
  87. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/github_ingest.py +0 -0
  88. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/graph_recon.py +0 -0
  89. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/graphify.py +0 -0
  90. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_actions.py +0 -0
  91. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_data/help.json +0 -0
  92. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/help_data/pages.json +0 -0
  93. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/helpdesk.py +0 -0
  94. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/helpdesk_kb.md +0 -0
  95. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/hooks/__init__.py +0 -0
  96. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/hooks/crucial_guard.py +0 -0
  97. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/instructions_template.py +0 -0
  98. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/intake.py +0 -0
  99. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ipc/__init__.py +0 -0
  100. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ipc/electron_bridge.py +0 -0
  101. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ipc/handlers.py +0 -0
  102. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/journal.py +0 -0
  103. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/local_exec.py +0 -0
  104. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/log_colors.py +0 -0
  105. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/memory_guard.py +0 -0
  106. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/model_policy.py +0 -0
  107. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/models/__init__.py +0 -0
  108. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/models/envelope.py +0 -0
  109. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/models/requests.py +0 -0
  110. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/models/responses.py +0 -0
  111. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/models/snapshots.py +0 -0
  112. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/phase_timer.py +0 -0
  113. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/plan_run.py +0 -0
  114. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/platform_compat.py +0 -0
  115. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/prd_progress.py +0 -0
  116. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/proof_readers.py +0 -0
  117. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/providers.py +0 -0
  118. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/py.typed +0 -0
  119. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/resume.py +0 -0
  120. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/router.py +0 -0
  121. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/schedule_tickets.py +0 -0
  122. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/schedule_timeline.py +0 -0
  123. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/scheduler.py +0 -0
  124. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/scope_plan.py +0 -0
  125. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/self_report.py +0 -0
  126. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/self_report_local.py +0 -0
  127. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/sse.py +0 -0
  128. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/swagger.py +0 -0
  129. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/task_file.py +0 -0
  130. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/task_types.py +0 -0
  131. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/test.py +0 -0
  132. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/test_env.py +0 -0
  133. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/test_pipeline.py +0 -0
  134. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ticket_board.py +0 -0
  135. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ticket_bulk.py +0 -0
  136. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ticket_fields.py +0 -0
  137. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ticket_plan.py +0 -0
  138. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ticket_pools.py +0 -0
  139. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/tickets.py +0 -0
  140. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/tiers/__init__.py +0 -0
  141. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/tiers/mini_agent.py +0 -0
  142. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/__init__.py +0 -0
  143. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/api.py +0 -0
  144. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/dashboard.py +0 -0
  145. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/health.py +0 -0
  146. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/ip_allowlist.py +0 -0
  147. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/jobs.py +0 -0
  148. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/models.py +0 -0
  149. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/runner.py +0 -0
  150. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/security.py +0 -0
  151. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/service.py +0 -0
  152. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/session.py +0 -0
  153. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/setup_manager.py +0 -0
  154. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/agents.html +0 -0
  155. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/app.js +0 -0
  156. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/chat.html +0 -0
  157. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/custom-agents.html +0 -0
  158. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/default-agents.html +0 -0
  159. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/faqs.html +0 -0
  160. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/help.html +0 -0
  161. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/index.html +0 -0
  162. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/report.html +0 -0
  163. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/runs.html +0 -0
  164. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/schedules.html +0 -0
  165. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/setup.html +0 -0
  166. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/styles.css +0 -0
  167. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/static/tickets.html +0 -0
  168. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/ui/swagger.py +0 -0
  169. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/updater.py +0 -0
  170. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/url_access.py +0 -0
  171. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/vps_health.py +0 -0
  172. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/vps_identity.py +0 -0
  173. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/sdk/write_hook.py +0 -0
  174. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/setup.cfg +0 -0
  175. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_claude_runs.py +0 -0
  176. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_collectors.py +0 -0
  177. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_core.py +0 -0
  178. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_live_tracking.py +0 -0
  179. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_macos.py +0 -0
  180. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_os_setup.py +0 -0
  181. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_activity_pipeline.py +0 -0
  182. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_activity.py +0 -0
  183. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_activity_tracking.py +0 -0
  184. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_chat_features.py +0 -0
  185. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_crud_cli.py +0 -0
  186. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_listing.py +0 -0
  187. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_prompt_async.py +0 -0
  188. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_prompt_models.py +0 -0
  189. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_run_ticket.py +0 -0
  190. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_schedules.py +0 -0
  191. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_sharing.py +0 -0
  192. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agent_workspace_settings.py +0 -0
  193. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_agents_connectors_builder.py +0 -0
  194. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_allowed_tools_config.py +0 -0
  195. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_approval_park.py +0 -0
  196. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_auto_agent_dispatch.py +0 -0
  197. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_auto_ticket_queue.py +0 -0
  198. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_backend_only_allowlist.py +0 -0
  199. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_browser_profile.py +0 -0
  200. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_cheap_tier.py +0 -0
  201. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_claude_usage_gate.py +0 -0
  202. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_client_jira_projects.py +0 -0
  203. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_config_token_diagnostics.py +0 -0
  204. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_configure_token_owner.py +0 -0
  205. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_console_encoding.py +0 -0
  206. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_crash_recovery.py +0 -0
  207. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_create_safe_retry.py +0 -0
  208. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_deferred_tickets.py +0 -0
  209. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_departments.py +0 -0
  210. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_done_transition.py +0 -0
  211. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_epic_decompose_run.py +0 -0
  212. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_epic_inherited_agent_id.py +0 -0
  213. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_epic_session_isolation.py +0 -0
  214. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_estimator.py +0 -0
  215. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_fallback_cli.py +0 -0
  216. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_fallback_cli_upgrade.py +0 -0
  217. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_fallback_rate_limit.py +0 -0
  218. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_faqs.py +0 -0
  219. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_firewall_open_on_update.py +0 -0
  220. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_formats.py +0 -0
  221. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_git_action.py +0 -0
  222. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_github_fetch.py +0 -0
  223. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_github_ingest.py +0 -0
  224. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_graph_off_by_default.py +0 -0
  225. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_graph_recon.py +0 -0
  226. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_graphify_build.py +0 -0
  227. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_graphify_hook_install.py +0 -0
  228. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_health.py +0 -0
  229. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_help_actions.py +0 -0
  230. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_help_attachments.py +0 -0
  231. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_help_questions.py +0 -0
  232. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_helpdesk.py +0 -0
  233. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_infographic_data.py +0 -0
  234. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_instructions_template.py +0 -0
  235. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_intake_job_outcome.py +0 -0
  236. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_intake_plan_review.py +0 -0
  237. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_journal.py +0 -0
  238. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_limit_fallback_handoff.py +0 -0
  239. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_local_exec_provider.py +0 -0
  240. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_log_colors_backlog.py +0 -0
  241. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_mcp_route_contract.py +0 -0
  242. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_memory_guard.py +0 -0
  243. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_model_policy.py +0 -0
  244. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_panel_help.py +0 -0
  245. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_panel_ticket_schedules.py +0 -0
  246. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_parallel_tickets.py +0 -0
  247. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_phase_timer.py +0 -0
  248. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_plan_ahead.py +0 -0
  249. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_plan_new_command.py +0 -0
  250. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_plan_run_activity.py +0 -0
  251. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_pool_pr_modes.py +0 -0
  252. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_pr_identity.py +0 -0
  253. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_prd_artifact.py +0 -0
  254. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_project_path_resolution.py +0 -0
  255. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_proof_readers.py +0 -0
  256. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_providers.py +0 -0
  257. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_quiet_run_log.py +0 -0
  258. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_recon_session_isolation.py +0 -0
  259. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_resume.py +0 -0
  260. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_router.py +0 -0
  261. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_run_auto_agent_only.py +0 -0
  262. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_run_outputs.py +0 -0
  263. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_run_verdict_is_honest.py +0 -0
  264. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_schedule_api.py +0 -0
  265. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_schedule_outputs_and_plans.py +0 -0
  266. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_schedule_tickets.py +0 -0
  267. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_schedule_timeline.py +0 -0
  268. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_scheduler.py +0 -0
  269. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_scheduler_transient_retry.py +0 -0
  270. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_self_report.py +0 -0
  271. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_service_token_warning.py +0 -0
  272. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_stale_panel_restart.py +0 -0
  273. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_swagger_command.py +0 -0
  274. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_task_file_and_plan_run.py +0 -0
  275. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_task_file_format_doc.py +0 -0
  276. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_theme_switch.py +0 -0
  277. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_board.py +0 -0
  278. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_bulk.py +0 -0
  279. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_cli.py +0 -0
  280. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_detail_view.py +0 -0
  281. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_fields.py +0 -0
  282. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_plan.py +0 -0
  283. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_pools.py +0 -0
  284. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_run_resolve_by_id.py +0 -0
  285. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_schedule_and_agent.py +0 -0
  286. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ticket_speed_fixes.py +0 -0
  287. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_tier_flag_parity.py +0 -0
  288. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ui_bruteforce_guard.py +0 -0
  289. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ui_gate.py +0 -0
  290. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ui_lifespan.py +0 -0
  291. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_ui_no_native_dialogs.py +0 -0
  292. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_update_timer.py +0 -0
  293. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_updater_extras.py +0 -0
  294. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_updater_ignores_cwd.py +0 -0
  295. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_updater_pep668.py +0 -0
  296. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_updater_reports_the_truth.py +0 -0
  297. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_url_access.py +0 -0
  298. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_version_flag.py +0 -0
  299. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_vps_health.py +0 -0
  300. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_vps_only_reporting.py +0 -0
  301. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_windows_loop_identity.py +0 -0
  302. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_windows_panel_task.py +0 -0
  303. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_windows_stop_and_pidfile.py +0 -0
  304. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/tests/test_windows_task_paths.py +0 -0
  305. {devops_bot_sdk-1.7.47 → devops_bot_sdk-1.7.48}/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.47
3
+ Version: 1.7.48
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.7.47
3
+ Version: 1.7.48
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
@@ -32,6 +32,7 @@ sdk/graphify.py
32
32
  sdk/help_actions.py
33
33
  sdk/helpdesk.py
34
34
  sdk/helpdesk_kb.md
35
+ sdk/install_marker.py
35
36
  sdk/instructions_template.py
36
37
  sdk/intake.py
37
38
  sdk/journal.py
@@ -226,6 +227,7 @@ tests/test_help_attachments.py
226
227
  tests/test_help_questions.py
227
228
  tests/test_helpdesk.py
228
229
  tests/test_infographic_data.py
230
+ tests/test_install_marker.py
229
231
  tests/test_instructions_template.py
230
232
  tests/test_intake_job_outcome.py
231
233
  tests/test_intake_plan_review.py
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.7.47
3
+ Version: 1.7.48
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.47" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
37
+ __version__ = "1.7.48" # 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
@@ -854,6 +854,12 @@ def main() -> None:
854
854
  from sdk.platform_compat import ensure_macos_fork_safety, ensure_utf8_stdio
855
855
  ensure_utf8_stdio()
856
856
 
857
+ # Record where this installation's scripts live (~/.agentos/install.json) so
858
+ # external tools (e.g. over a minimal-PATH SSH session) can find the CLI.
859
+ # Never raises, never prints; rewrites only when something changed.
860
+ from sdk.install_marker import record_install_location
861
+ record_install_location()
862
+
857
863
  # macOS: keep the background daemon from aborting ("Python quit unexpectedly")
858
864
  # when it does networking after the double-fork. May re-exec once; must run
859
865
  # before any fork or objc-linked import.
@@ -8,6 +8,14 @@ the "verb".
8
8
 
9
9
  Command surface:
10
10
 
11
+ agentos where [--json]
12
+ Where THIS installation lives: the directory holding the agentos /
13
+ agentos-auto scripts (bin_dir), the Python running it, the SDK version,
14
+ and the path of ~/.agentos/install.json — which every entry point keeps
15
+ current and this command refreshes. For external tools (the AI Draftsman
16
+ DevOps Bot SDK connector) that reach the machine over a minimal-PATH SSH
17
+ session. See sdk.install_marker.
18
+
11
19
  agentos configure [--rotate]
12
20
  Store (or replace) the co_<uuid>_<hex> backend token. See
13
21
  sdk.config.configure_cli.
@@ -173,6 +181,12 @@ def main() -> None:
173
181
  from sdk.platform_compat import ensure_utf8_stdio
174
182
  ensure_utf8_stdio()
175
183
 
184
+ # Record where this installation's scripts live (~/.agentos/install.json) so
185
+ # external tools (e.g. over a minimal-PATH SSH session) can find the CLI.
186
+ # Never raises, never prints; rewrites only when something changed.
187
+ from sdk.install_marker import record_install_location
188
+ record_install_location()
189
+
176
190
  argv = sys.argv[1:]
177
191
  if not argv:
178
192
  _print_usage()
@@ -185,6 +199,12 @@ def main() -> None:
185
199
  print(version_line())
186
200
  return
187
201
 
202
+ if noun == "where":
203
+ # Where this installation lives (bin_dir, python, version) + the path of
204
+ # ~/.agentos/install.json, which it refreshes. `--json` for machines.
205
+ from sdk.install_marker import where_cli
206
+ sys.exit(where_cli(rest))
207
+
188
208
  if noun == "configure":
189
209
  from sdk.config import configure_cli
190
210
  configure_cli(rotate="--rotate" in sys.argv)
@@ -274,9 +294,10 @@ def main() -> None:
274
294
 
275
295
 
276
296
  def _print_usage() -> None:
277
- print("usage: agentos <configure|chat|agent|ticket|integration|default-agents|agentd|github|report|browser|fallback|help|doctor|firewall|allow-ip|activity-setup|swagger> ...")
297
+ print("usage: agentos <where|configure|chat|agent|ticket|integration|default-agents|agentd|github|report|browser|fallback|help|doctor|firewall|allow-ip|activity-setup|swagger> ...")
278
298
  print()
279
299
  print(' agentos version (or --version) # installed SDK version, Python and install path')
300
+ print(' agentos where [--json] # bin dir of agentos/agentos-auto, python, version; refreshes ~/.agentos/install.json')
280
301
  print(' agentos help "<your problem>" [--file PATH]… # DevOps Bot Help: reads your logs + the SDK (+ screenshots/logs you attach)')
281
302
  print(" agentos doctor # collect a diagnostics bundle to send to your admin (no AI)")
282
303
  print(" agentos configure [--rotate]")
@@ -53,6 +53,15 @@
53
53
  "latest_pr": 164,
54
54
  "latest_date": "2026-10-24"
55
55
  },
56
+ {
57
+ "area": "Agents",
58
+ "changes_30d": 2,
59
+ "features_30d": 1,
60
+ "fixes_30d": 0,
61
+ "latest": "record install location in ~/.agentos/install.json + agentos where",
62
+ "latest_pr": 191,
63
+ "latest_date": "2026-11-03"
64
+ },
56
65
  {
57
66
  "area": "Schedules",
58
67
  "changes_30d": 2,
@@ -62,15 +71,6 @@
62
71
  "latest_pr": 163,
63
72
  "latest_date": "2026-10-23"
64
73
  },
65
- {
66
- "area": "Agents",
67
- "changes_30d": 1,
68
- "features_30d": 0,
69
- "fixes_30d": 0,
70
- "latest": "APPR-539: [ST0135] Early years educator - Course Orchestrator + 69 item agents",
71
- "latest_pr": 146,
72
- "latest_date": "2026-10-20"
73
- },
74
74
  {
75
75
  "area": "Daemon",
76
76
  "changes_30d": 1,
@@ -19,6 +19,16 @@
19
19
  "doc": "https://github.com/consultancy-outfit/DevOpsBot-SDK/blob/main/docs/COMMANDS.md",
20
20
  "id": "agentos version"
21
21
  },
22
+ {
23
+ "command": "agentos where",
24
+ "syntax": "agentos where [--json]",
25
+ "program": "agentos",
26
+ "area": "Other",
27
+ "description": "bin dir of agentos/agentos-auto, python, version + ~/.agentos/install.json (refreshed)",
28
+ "valid": true,
29
+ "doc": "https://github.com/consultancy-outfit/DevOpsBot-SDK/blob/main/docs/COMMANDS.md",
30
+ "id": "agentos where"
31
+ },
22
32
  {
23
33
  "command": "agentos agent",
24
34
  "syntax": "agentos agent list",
@@ -1,4 +1,14 @@
1
1
  [
2
+ {
3
+ "pr": 191,
4
+ "date": "2026-11-03",
5
+ "merged_at": "2026-11-03T14:46:05+05:00",
6
+ "type": "Feature",
7
+ "area": "Agents",
8
+ "title": "record install location in ~/.agentos/install.json + agentos where",
9
+ "version": "1.7.48",
10
+ "url": "https://github.com/consultancy-outfit/DevOpsBot-SDK/pull/191"
11
+ },
2
12
  {
3
13
  "pr": 190,
4
14
  "date": "2026-10-30",
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "version": "1.7.48",
4
+ "commit": "84377c8",
5
+ "pushed_at": "2026-11-03T14:46:05+05:00",
6
+ "generated_at": "2026-11-03T09:47:28+00:00",
7
+ "commands": 60,
8
+ "commands_invalid": 0,
9
+ "commands_undocumented": 0,
10
+ "panel_pages": 11,
11
+ "tests": 2613,
12
+ "prs_7d": 11,
13
+ "prs_30d": 43,
14
+ "features_30d": 13,
15
+ "fixes_30d": 18
16
+ }
17
+ ]
@@ -0,0 +1,175 @@
1
+ """Record where THIS installation's console scripts live: ``~/.agentos/install.json``.
2
+
3
+ Why: tools outside the SDK (the AI Draftsman "DevOps Bot SDK" connector, which
4
+ SSHes in and runs ``agentos …`` / ``agentos-auto …``) need to find the CLI. A
5
+ non-interactive SSH session usually has a minimal PATH, and the SDK may be
6
+ installed globally (system pip, ``pip --user`` → ``~/.local/bin``, pipx) or in a
7
+ virtualenv anywhere on disk (the bootstrap's ``~/agentsystem/venv``, a project's
8
+ ``.venv``). The SDK is the one thing that knows where it is, so it writes it down
9
+ every time one of its entry points starts:
10
+
11
+ {"bin_dir": "...", "python": "...", "version": "...", "written_at": "..."}
12
+
13
+ ``bin_dir`` is the directory holding the ``agentos`` and ``agentos-auto`` scripts.
14
+ It is NOT symlink-resolved: in a venv ``bin/python`` is a symlink to the base
15
+ interpreter, and resolving it would point at a directory with no ``agentos`` in it.
16
+
17
+ Contract: :func:`record_install_location` never raises and never prints — a
18
+ read-only home, a full disk or a missing directory must not break any command.
19
+ The file is rewritten only when something other than ``written_at`` changed, so
20
+ startup stays cheap. Override the directory with ``AGENTOS_HOME`` (the same
21
+ override ``sdk.journal`` and ``sdk.providers`` honour).
22
+ """
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ import os
27
+ import sys
28
+ import sysconfig
29
+ from datetime import datetime, timezone
30
+ from pathlib import Path
31
+ from typing import Any
32
+
33
+ MARKER_NAME = "install.json"
34
+
35
+
36
+ def _agentos_dir() -> Path:
37
+ return Path(os.environ.get("AGENTOS_HOME") or (Path.home() / ".agentos"))
38
+
39
+
40
+ def marker_path() -> Path:
41
+ """Where the marker lives (``$AGENTOS_HOME/install.json``, default ``~/.agentos``)."""
42
+ return _agentos_dir() / MARKER_NAME
43
+
44
+
45
+ def _script_names() -> tuple[str, ...]:
46
+ return ("agentos.exe", "agentos") if os.name == "nt" else ("agentos",)
47
+
48
+
49
+ def _has_agentos(directory: Path) -> bool:
50
+ try:
51
+ return any((directory / name).is_file() for name in _script_names())
52
+ except OSError:
53
+ return False
54
+
55
+
56
+ def _abs_dir(path: str | os.PathLike[str]) -> Path:
57
+ # Absolute, normalised — but NOT symlink-resolved (keeps venv paths intact).
58
+ return Path(os.path.abspath(os.fspath(path)))
59
+
60
+
61
+ def _sysconfig_script_dirs() -> list[Path]:
62
+ dirs: list[Path] = []
63
+ try:
64
+ p = sysconfig.get_path("scripts")
65
+ if p:
66
+ dirs.append(_abs_dir(p))
67
+ except (KeyError, ValueError, OSError):
68
+ pass
69
+ try:
70
+ scheme = sysconfig.get_preferred_scheme("user")
71
+ except (KeyError, ValueError, AttributeError):
72
+ scheme = f"{os.name}_user"
73
+ try:
74
+ p = sysconfig.get_path("scripts", scheme)
75
+ if p:
76
+ dirs.append(_abs_dir(p))
77
+ except (KeyError, ValueError, OSError):
78
+ pass
79
+ return dirs
80
+
81
+
82
+ def detect_bin_dir(argv0: str | None = None) -> Path:
83
+ """The directory containing this installation's ``agentos`` script.
84
+
85
+ (a) the directory of ``argv[0]`` when it holds ``agentos``; else (b) the
86
+ interpreter's scripts dir, then the user-scheme scripts dir (``pip --user``),
87
+ first one holding ``agentos``; else (c) the directory of ``sys.executable``.
88
+ """
89
+ if argv0 is None:
90
+ argv0 = sys.argv[0] if sys.argv else ""
91
+ if argv0:
92
+ try:
93
+ candidate = _abs_dir(argv0).parent
94
+ if _has_agentos(candidate):
95
+ return candidate
96
+ except (OSError, ValueError):
97
+ pass
98
+ for candidate in _sysconfig_script_dirs():
99
+ if _has_agentos(candidate):
100
+ return candidate
101
+ return _abs_dir(sys.executable or "python").parent
102
+
103
+
104
+ def current_install(argv0: str | None = None) -> dict[str, Any]:
105
+ """The marker's content, minus ``written_at``."""
106
+ from sdk import __version__
107
+ return {
108
+ "bin_dir": str(detect_bin_dir(argv0)),
109
+ "python": sys.executable,
110
+ "version": __version__,
111
+ }
112
+
113
+
114
+ def _read(path: Path) -> dict[str, Any] | None:
115
+ try:
116
+ data = json.loads(path.read_text(encoding="utf-8"))
117
+ return data if isinstance(data, dict) else None
118
+ except (OSError, ValueError):
119
+ return None
120
+
121
+
122
+ def record_install_location(path: Path | None = None,
123
+ argv0: str | None = None) -> dict[str, Any] | None:
124
+ """Write ``install.json`` if it is missing or stale. Never raises, never prints.
125
+
126
+ Returns the record now on disk (or the one that would have been written, when
127
+ the write failed), or ``None`` if even detection failed.
128
+ """
129
+ try:
130
+ target = path if path is not None else marker_path()
131
+ info = current_install(argv0)
132
+ existing = _read(target)
133
+ if existing is not None and all(existing.get(k) == v for k, v in info.items()) \
134
+ and existing.get("written_at"):
135
+ return existing
136
+ record = dict(info)
137
+ record["written_at"] = datetime.now(timezone.utc).isoformat(timespec="seconds")
138
+ try:
139
+ target.parent.mkdir(parents=True, exist_ok=True)
140
+ tmp = target.with_name(f".{target.name}.{os.getpid()}.tmp")
141
+ try:
142
+ tmp.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8")
143
+ try:
144
+ os.chmod(tmp, 0o644)
145
+ except OSError:
146
+ pass
147
+ os.replace(tmp, target)
148
+ finally:
149
+ try:
150
+ if tmp.exists():
151
+ tmp.unlink()
152
+ except OSError:
153
+ pass
154
+ except OSError:
155
+ pass
156
+ return record
157
+ except Exception: # noqa: BLE001 — must never break a command
158
+ return None
159
+
160
+
161
+ def where_cli(argv: list[str]) -> int:
162
+ """``agentos where [--json]``: where this installation lives (refreshes install.json)."""
163
+ record = record_install_location() or {}
164
+ try:
165
+ path = str(marker_path())
166
+ except Exception: # noqa: BLE001
167
+ path = ""
168
+ if "--json" in argv:
169
+ print(json.dumps(record, indent=2))
170
+ return 0
171
+ print(f"bin_dir: {record.get('bin_dir', '')}")
172
+ print(f"python: {record.get('python', '')}")
173
+ print(f"version: {record.get('version', '')}")
174
+ print(f"install.json: {path}")
175
+ return 0
@@ -1965,6 +1965,12 @@ def main() -> None:
1965
1965
  from sdk.platform_compat import ensure_macos_fork_safety, ensure_utf8_stdio
1966
1966
  ensure_utf8_stdio()
1967
1967
 
1968
+ # Record where this installation's scripts live (~/.agentos/install.json) so
1969
+ # external tools (e.g. over a minimal-PATH SSH session) can find the CLI.
1970
+ # Never raises, never prints; rewrites only when something changed.
1971
+ from sdk.install_marker import record_install_location
1972
+ record_install_location()
1973
+
1968
1974
  # macOS: keep the background daemon from aborting ("Python quit unexpectedly")
1969
1975
  # when it does networking after the double-fork. May re-exec once; must run
1970
1976
  # before any fork or objc-linked import.
@@ -275,6 +275,12 @@ def main() -> None:
275
275
  from sdk.platform_compat import ensure_utf8_stdio
276
276
  ensure_utf8_stdio()
277
277
 
278
+ # Record where this installation's scripts live (~/.agentos/install.json) so
279
+ # external tools (e.g. over a minimal-PATH SSH session) can find the CLI.
280
+ # Never raises, never prints; rewrites only when something changed.
281
+ from sdk.install_marker import record_install_location
282
+ record_install_location()
283
+
278
284
  argv = sys.argv[1:]
279
285
  cmd = argv[0] if argv and not argv[0].startswith("-") else "serve"
280
286
  if cmd in ("install", "uninstall", "status"):
@@ -0,0 +1,169 @@
1
+ """`~/.agentos/install.json` — where THIS installation's console scripts live, for
2
+ external tools (the AI Draftsman DevOps Bot SDK connector) that reach the machine
3
+ over a minimal-PATH SSH session — and `agentos where`."""
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ from sdk import __version__, cli, install_marker
12
+
13
+ SCRIPT = "agentos.exe" if os.name == "nt" else "agentos"
14
+
15
+
16
+ def _venv(tmp_path: Path, name: str = "venv") -> Path:
17
+ bin_dir = tmp_path / name / "bin"
18
+ bin_dir.mkdir(parents=True)
19
+ (bin_dir / SCRIPT).write_text("#!/bin/sh\n")
20
+ (bin_dir / "agentos-auto").write_text("#!/bin/sh\n")
21
+ return bin_dir
22
+
23
+
24
+ @pytest.fixture
25
+ def no_sysconfig(monkeypatch):
26
+ monkeypatch.setattr(install_marker, "_sysconfig_script_dirs", lambda: [])
27
+
28
+
29
+ def test_bin_dir_is_argv0s_directory_in_a_venv(tmp_path, no_sysconfig):
30
+ bin_dir = _venv(tmp_path)
31
+ assert install_marker.detect_bin_dir(str(bin_dir / "agentos")) == bin_dir
32
+
33
+
34
+ def test_bin_dir_keeps_the_venv_path_even_when_python_is_a_symlink(tmp_path, monkeypatch, no_sysconfig):
35
+ # A venv's python is a symlink to the base interpreter; resolving it would lose
36
+ # the venv. argv[0]'s directory must be kept as-is.
37
+ bin_dir = _venv(tmp_path)
38
+ real = tmp_path / "base" / "python3"
39
+ real.parent.mkdir()
40
+ real.write_text("")
41
+ link = bin_dir / "python"
42
+ try:
43
+ link.symlink_to(real)
44
+ except (OSError, NotImplementedError):
45
+ pytest.skip("symlinks unavailable")
46
+ monkeypatch.setattr(sys, "executable", str(link))
47
+ assert install_marker.detect_bin_dir("/nonexistent/agentos-ui") == bin_dir
48
+
49
+
50
+ def test_falls_back_to_sysconfig_scripts_dir(tmp_path, monkeypatch):
51
+ user_bin = _venv(tmp_path, "local")
52
+ empty = tmp_path / "empty"
53
+ empty.mkdir()
54
+ monkeypatch.setattr(install_marker, "_sysconfig_script_dirs", lambda: [empty, user_bin])
55
+ # argv[0] somewhere with no agentos next to it (e.g. `python -m sdk.cli`)
56
+ assert install_marker.detect_bin_dir(str(tmp_path / "elsewhere" / "cli.py")) == user_bin
57
+
58
+
59
+ def test_sysconfig_user_scheme_is_consulted(monkeypatch):
60
+ seen = []
61
+
62
+ def fake_get_path(name, scheme=None):
63
+ seen.append(scheme)
64
+ if scheme is not None:
65
+ raise KeyError(scheme) # a scheme this Python lacks must not raise
66
+ return "/somewhere/bin"
67
+
68
+ monkeypatch.setattr(install_marker.sysconfig, "get_path", fake_get_path)
69
+ assert install_marker._sysconfig_script_dirs() == [Path("/somewhere/bin")]
70
+ assert len(seen) == 2 and seen[1] is not None
71
+
72
+
73
+ def test_falls_back_to_sys_executable_dir(tmp_path, monkeypatch, no_sysconfig):
74
+ py_dir = tmp_path / "py" / "bin"
75
+ py_dir.mkdir(parents=True)
76
+ monkeypatch.setattr(sys, "executable", str(py_dir / "python3"))
77
+ assert install_marker.detect_bin_dir(str(tmp_path / "nowhere" / "x")) == py_dir
78
+
79
+
80
+ def test_writes_the_record_atomically(tmp_path, no_sysconfig):
81
+ bin_dir = _venv(tmp_path)
82
+ target = tmp_path / "home" / ".agentos" / "install.json"
83
+ rec = install_marker.record_install_location(target, argv0=str(bin_dir / "agentos"))
84
+ on_disk = json.loads(target.read_text())
85
+ assert on_disk == rec
86
+ assert set(on_disk) == {"bin_dir", "python", "version", "written_at"}
87
+ assert on_disk["bin_dir"] == str(bin_dir)
88
+ assert on_disk["python"] == sys.executable
89
+ assert on_disk["version"] == __version__
90
+ assert on_disk["written_at"].endswith("+00:00")
91
+ # No temp file left behind.
92
+ assert [p.name for p in target.parent.iterdir()] == ["install.json"]
93
+
94
+
95
+ def test_no_rewrite_when_unchanged(tmp_path, no_sysconfig):
96
+ bin_dir = _venv(tmp_path)
97
+ target = tmp_path / "install.json"
98
+ first = install_marker.record_install_location(target, argv0=str(bin_dir / "agentos"))
99
+ before = target.stat().st_mtime_ns
100
+ target.write_text(json.dumps({**first, "written_at": "2000-01-01T00:00:00+00:00"}))
101
+ marked = target.stat().st_mtime_ns
102
+ second = install_marker.record_install_location(target, argv0=str(bin_dir / "agentos"))
103
+ assert second["written_at"] == "2000-01-01T00:00:00+00:00"
104
+ assert target.stat().st_mtime_ns == marked
105
+ assert before # sanity
106
+
107
+
108
+ def test_rewrites_when_the_install_moved(tmp_path, no_sysconfig):
109
+ old, new = _venv(tmp_path, "old"), _venv(tmp_path, "new")
110
+ target = tmp_path / "install.json"
111
+ install_marker.record_install_location(target, argv0=str(old / "agentos"))
112
+ install_marker.record_install_location(target, argv0=str(new / "agentos"))
113
+ assert json.loads(target.read_text())["bin_dir"] == str(new)
114
+
115
+
116
+ def test_never_raises_when_home_is_unwritable(tmp_path, monkeypatch, capsys):
117
+ blocker = tmp_path / "file"
118
+ blocker.write_text("") # a FILE where the directory should be → mkdir fails
119
+ rec = install_marker.record_install_location(blocker / ".agentos" / "install.json")
120
+ assert rec is not None and "bin_dir" in rec
121
+ monkeypatch.setattr(install_marker, "current_install",
122
+ lambda argv0=None: (_ for _ in ()).throw(RuntimeError("boom")))
123
+ assert install_marker.record_install_location(tmp_path / "x.json") is None
124
+ assert capsys.readouterr() == ("", "")
125
+
126
+
127
+ @pytest.mark.skipif(os.name == "nt" or (hasattr(os, "geteuid") and os.geteuid() == 0),
128
+ reason="needs POSIX permissions and a non-root user")
129
+ def test_never_raises_on_a_read_only_directory(tmp_path):
130
+ ro = tmp_path / "ro"
131
+ ro.mkdir()
132
+ ro.chmod(0o555)
133
+ try:
134
+ assert install_marker.record_install_location(ro / "install.json") is not None
135
+ assert not (ro / "install.json").exists()
136
+ finally:
137
+ ro.chmod(0o755)
138
+
139
+
140
+ def test_agentos_where_json(tmp_path, monkeypatch, capsys, no_sysconfig):
141
+ bin_dir = _venv(tmp_path)
142
+ monkeypatch.setattr(sys, "argv", [str(bin_dir / "agentos"), "where", "--json"])
143
+ with pytest.raises(SystemExit) as exc:
144
+ cli.main()
145
+ assert exc.value.code == 0
146
+ out = json.loads(capsys.readouterr().out)
147
+ assert out["bin_dir"] == str(bin_dir)
148
+ assert out["version"] == __version__
149
+ assert out["python"] == sys.executable
150
+ assert json.loads(install_marker.marker_path().read_text()) == out
151
+
152
+
153
+ def test_agentos_where_plain(tmp_path, monkeypatch, capsys, no_sysconfig):
154
+ bin_dir = _venv(tmp_path)
155
+ monkeypatch.setattr(sys, "argv", [str(bin_dir / "agentos"), "where"])
156
+ with pytest.raises(SystemExit):
157
+ cli.main()
158
+ out = capsys.readouterr().out
159
+ assert f"bin_dir: {bin_dir}" in out
160
+ assert f"install.json: {install_marker.marker_path()}" in out
161
+
162
+
163
+ def test_version_output_is_unchanged_and_records_the_marker(monkeypatch, capsys):
164
+ monkeypatch.setattr(sys, "argv", ["agentos", "version"])
165
+ cli.main()
166
+ out = capsys.readouterr().out
167
+ assert out.startswith(f"devops-bot-sdk {__version__} · Python ")
168
+ assert out.count("\n") == 1
169
+ assert install_marker.marker_path().is_file()
@@ -1,17 +0,0 @@
1
- [
2
- {
3
- "version": "1.7.47",
4
- "commit": "226a619",
5
- "pushed_at": "2026-10-30T14:48:32+05:00",
6
- "generated_at": "2026-10-30T09:50:43+00:00",
7
- "commands": 59,
8
- "commands_invalid": 0,
9
- "commands_undocumented": 0,
10
- "panel_pages": 11,
11
- "tests": 2600,
12
- "prs_7d": 26,
13
- "prs_30d": 42,
14
- "features_30d": 12,
15
- "fixes_30d": 18
16
- }
17
- ]