devops-bot-sdk 1.6.60__tar.gz → 1.6.64__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 (230) hide show
  1. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/PKG-INFO +1 -1
  2. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
  3. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/SOURCES.txt +2 -0
  4. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/__init__.py +2 -2
  5. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/windows_eventlog.py +6 -4
  6. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/cli.py +344 -33
  7. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/client.py +131 -10
  8. devops_bot_sdk-1.6.64/sdk/custom_agents.py +507 -0
  9. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/tickets.py +81 -48
  10. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/api.py +84 -0
  11. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/models.py +35 -0
  12. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/app.js +223 -4
  13. devops_bot_sdk-1.6.64/sdk/ui/static/custom-agents.html +152 -0
  14. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/styles.css +10 -0
  15. devops_bot_sdk-1.6.64/tests/test_agent_crud_cli.py +740 -0
  16. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ticket_cli.py +138 -57
  17. devops_bot_sdk-1.6.60/sdk/ui/static/custom-agents.html +0 -84
  18. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/README.md +0 -0
  19. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  20. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  21. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/requires.txt +0 -0
  22. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  23. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/pyproject.toml +0 -0
  24. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/__init__.py +0 -0
  25. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/classifier.py +0 -0
  26. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/__init__.py +0 -0
  27. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/common.py +0 -0
  28. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/linux_auditd.py +0 -0
  29. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/macos_eslogger.py +0 -0
  30. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/models.py +0 -0
  31. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/os_setup.py +0 -0
  32. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/recorder.py +0 -0
  33. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/redact.py +0 -0
  34. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/settings.py +0 -0
  35. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/shipper.py +0 -0
  36. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/activity/spool.py +0 -0
  37. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agentd.py +0 -0
  38. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/__init__.py +0 -0
  39. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/activity.py +0 -0
  40. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/builder.py +0 -0
  41. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/chat.py +0 -0
  42. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/connectors.py +0 -0
  43. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/__init__.py +0 -0
  44. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/claude_code.py +0 -0
  45. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/http.py +0 -0
  46. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/mcp.py +0 -0
  47. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/n8n.py +0 -0
  48. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/engines/shell.py +0 -0
  49. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/integrations.py +0 -0
  50. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/inventory.py +0 -0
  51. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/library/__init__.py +0 -0
  52. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/manifest.py +0 -0
  53. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_studio.py +0 -0
  54. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_template.py +0 -0
  55. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_vars.py +0 -0
  56. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/run_log.py +0 -0
  57. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/schedules.py +0 -0
  58. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/secrets.py +0 -0
  59. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/ticket_run.py +0 -0
  60. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/usage.py +0 -0
  61. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/agents/varstore.py +0 -0
  62. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/browser_profile.py +0 -0
  63. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/collectors/__init__.py +0 -0
  64. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/collectors/files.py +0 -0
  65. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/collectors/process.py +0 -0
  66. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/collectors/screenshot.py +0 -0
  67. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/config.py +0 -0
  68. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/crucial.py +0 -0
  69. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/departments.py +0 -0
  70. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/__init__.py +0 -0
  71. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/assets.py +0 -0
  72. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/bootstrap.py +0 -0
  73. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/browser.py +0 -0
  74. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/compare.py +0 -0
  75. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/design_verify/loop.py +0 -0
  76. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/estimator.py +0 -0
  77. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/exceptions.py +0 -0
  78. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/firewall.py +0 -0
  79. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/formats.py +0 -0
  80. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/git_ops.py +0 -0
  81. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/github_fetch.py +0 -0
  82. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/github_ingest.py +0 -0
  83. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/graph_recon.py +0 -0
  84. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/graphify.py +0 -0
  85. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/hooks/__init__.py +0 -0
  86. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/hooks/crucial_guard.py +0 -0
  87. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/intake.py +0 -0
  88. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ipc/__init__.py +0 -0
  89. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ipc/electron_bridge.py +0 -0
  90. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ipc/handlers.py +0 -0
  91. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/journal.py +0 -0
  92. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/local_exec.py +0 -0
  93. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/memory_guard.py +0 -0
  94. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/models/__init__.py +0 -0
  95. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/models/envelope.py +0 -0
  96. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/models/requests.py +0 -0
  97. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/models/responses.py +0 -0
  98. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/models/snapshots.py +0 -0
  99. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/phase_timer.py +0 -0
  100. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/plan_run.py +0 -0
  101. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/platform_compat.py +0 -0
  102. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/prd_progress.py +0 -0
  103. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/proof_readers.py +0 -0
  104. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/providers.py +0 -0
  105. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/py.typed +0 -0
  106. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/resume.py +0 -0
  107. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/router.py +0 -0
  108. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/run_auto.py +0 -0
  109. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/scheduler.py +0 -0
  110. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/self_report.py +0 -0
  111. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/self_report_local.py +0 -0
  112. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/sse.py +0 -0
  113. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/swagger.py +0 -0
  114. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/task_file.py +0 -0
  115. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/task_types.py +0 -0
  116. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/test.py +0 -0
  117. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/test_pipeline.py +0 -0
  118. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ticket_fields.py +0 -0
  119. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/tiers/__init__.py +0 -0
  120. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/tiers/mini_agent.py +0 -0
  121. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/__init__.py +0 -0
  122. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/dashboard.py +0 -0
  123. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/health.py +0 -0
  124. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/ip_allowlist.py +0 -0
  125. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/jobs.py +0 -0
  126. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/runner.py +0 -0
  127. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/security.py +0 -0
  128. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/server.py +0 -0
  129. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/service.py +0 -0
  130. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/session.py +0 -0
  131. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/setup_manager.py +0 -0
  132. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/agents.html +0 -0
  133. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/chat.html +0 -0
  134. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/default-agents.html +0 -0
  135. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/index.html +0 -0
  136. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/report.html +0 -0
  137. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/runs.html +0 -0
  138. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/schedules.html +0 -0
  139. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/setup.html +0 -0
  140. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/static/tickets.html +0 -0
  141. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/ui/swagger.py +0 -0
  142. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/updater.py +0 -0
  143. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/url_access.py +0 -0
  144. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/vendor/aidraftsman-cli-0.1.0.tgz +0 -0
  145. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/vps_health.py +0 -0
  146. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/sdk/write_hook.py +0 -0
  147. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/setup.cfg +0 -0
  148. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_activity_collectors.py +0 -0
  149. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_activity_core.py +0 -0
  150. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_activity_macos.py +0 -0
  151. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_activity_os_setup.py +0 -0
  152. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_activity_pipeline.py +0 -0
  153. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_activity.py +0 -0
  154. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_activity_tracking.py +0 -0
  155. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_chat_features.py +0 -0
  156. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_listing.py +0 -0
  157. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_prompt_async.py +0 -0
  158. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_prompt_models.py +0 -0
  159. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_run_ticket.py +0 -0
  160. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_schedules.py +0 -0
  161. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agent_workspace_settings.py +0 -0
  162. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_agents_connectors_builder.py +0 -0
  163. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_allowed_tools_config.py +0 -0
  164. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_auto_agent_dispatch.py +0 -0
  165. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_browser_profile.py +0 -0
  166. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_cheap_tier.py +0 -0
  167. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_client_jira_projects.py +0 -0
  168. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_config_token_diagnostics.py +0 -0
  169. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_configure_token_owner.py +0 -0
  170. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_console_encoding.py +0 -0
  171. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_crash_recovery.py +0 -0
  172. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_departments.py +0 -0
  173. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_done_transition.py +0 -0
  174. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_epic_decompose_run.py +0 -0
  175. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_epic_inherited_agent_id.py +0 -0
  176. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_epic_session_isolation.py +0 -0
  177. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_estimator.py +0 -0
  178. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_fallback_cli.py +0 -0
  179. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_firewall_open_on_update.py +0 -0
  180. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_formats.py +0 -0
  181. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_git_action.py +0 -0
  182. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_github_fetch.py +0 -0
  183. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_github_ingest.py +0 -0
  184. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_graph_recon.py +0 -0
  185. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_graphify_build.py +0 -0
  186. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_graphify_hook_install.py +0 -0
  187. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_health.py +0 -0
  188. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_intake_job_outcome.py +0 -0
  189. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_intake_plan_review.py +0 -0
  190. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_journal.py +0 -0
  191. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_local_exec_provider.py +0 -0
  192. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_mcp_route_contract.py +0 -0
  193. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_memory_guard.py +0 -0
  194. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_phase_timer.py +0 -0
  195. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_plan_new_command.py +0 -0
  196. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_plan_run_activity.py +0 -0
  197. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_pr_identity.py +0 -0
  198. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_prd_artifact.py +0 -0
  199. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_project_path_resolution.py +0 -0
  200. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_proof_readers.py +0 -0
  201. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_providers.py +0 -0
  202. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_recon_session_isolation.py +0 -0
  203. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_resume.py +0 -0
  204. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_router.py +0 -0
  205. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_run_auto_agent_only.py +0 -0
  206. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_run_outputs.py +0 -0
  207. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_run_verdict_is_honest.py +0 -0
  208. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_schedule_api.py +0 -0
  209. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_schedule_outputs_and_plans.py +0 -0
  210. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_scheduler.py +0 -0
  211. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_self_report.py +0 -0
  212. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_service_token_warning.py +0 -0
  213. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_stale_panel_restart.py +0 -0
  214. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_swagger_command.py +0 -0
  215. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_task_file_and_plan_run.py +0 -0
  216. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_task_file_format_doc.py +0 -0
  217. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ticket_fields.py +0 -0
  218. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ticket_run_resolve_by_id.py +0 -0
  219. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ticket_speed_fixes.py +0 -0
  220. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_tier_flag_parity.py +0 -0
  221. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ui_gate.py +0 -0
  222. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_ui_lifespan.py +0 -0
  223. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_update_timer.py +0 -0
  224. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_updater_extras.py +0 -0
  225. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_updater_pep668.py +0 -0
  226. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_updater_reports_the_truth.py +0 -0
  227. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_url_access.py +0 -0
  228. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_vps_health.py +0 -0
  229. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/tests/test_windows_loop_identity.py +0 -0
  230. {devops_bot_sdk-1.6.60 → devops_bot_sdk-1.6.64}/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.6.60
3
+ Version: 1.6.64
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.6.60
3
+ Version: 1.6.64
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
@@ -13,6 +13,7 @@ sdk/cli.py
13
13
  sdk/client.py
14
14
  sdk/config.py
15
15
  sdk/crucial.py
16
+ sdk/custom_agents.py
16
17
  sdk/departments.py
17
18
  sdk/estimator.py
18
19
  sdk/exceptions.py
@@ -147,6 +148,7 @@ tests/test_activity_pipeline.py
147
148
  tests/test_agent_activity.py
148
149
  tests/test_agent_activity_tracking.py
149
150
  tests/test_agent_chat_features.py
151
+ tests/test_agent_crud_cli.py
150
152
  tests/test_agent_listing.py
151
153
  tests/test_agent_prompt_async.py
152
154
  tests/test_agent_prompt_models.py
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.6.60
3
+ Version: 1.6.64
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.6.60" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
37
+ __version__ = "1.6.64" # 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
@@ -72,9 +72,9 @@ class WinEvent:
72
72
  data: dict[str, str]
73
73
 
74
74
 
75
- def parse_events(xml_text: str) -> list[WinEvent]:
75
+ def parse_events(xml_text: str | None) -> list[WinEvent]:
76
76
  """Parse ``wevtutil qe ... /f:xml`` output (a bare run of ``<Event>`` elements)."""
77
- xml_text = xml_text.strip()
77
+ xml_text = (xml_text or "").strip()
78
78
  if not xml_text:
79
79
  return []
80
80
  root = ET.fromstring(f"<Events>{xml_text}</Events>")
@@ -302,7 +302,8 @@ class WindowsEventLogCollector:
302
302
  xpath = f"*[System[({ids}) and EventRecordID>{after}]]"
303
303
  proc = subprocess.run(
304
304
  ["wevtutil", "qe", "Security", f"/q:{xpath}", "/f:xml", f"/c:{count}"],
305
- capture_output=True, text=True, timeout=60, check=False,
305
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
306
+ timeout=60, check=False,
306
307
  )
307
308
  if proc.returncode != 0:
308
309
  raise RuntimeError(proc.stderr.strip() or f"wevtutil exited {proc.returncode}")
@@ -311,7 +312,8 @@ class WindowsEventLogCollector:
311
312
  def _latest_record_id(self) -> int:
312
313
  out = subprocess.run(
313
314
  ["wevtutil", "qe", "Security", "/f:xml", "/c:1", "/rd:true"],
314
- capture_output=True, text=True, timeout=60, check=False,
315
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
316
+ timeout=60, check=False,
315
317
  ).stdout
316
318
  events = parse_events(out)
317
319
  return events[0].record_id if events else 0
@@ -20,16 +20,28 @@ Command surface:
20
20
  runs in createdAt order behind anything already queued.
21
21
  See sdk.intake.chat_cli.
22
22
 
23
- agentos agent new
24
- Interactive wizard (input() prompts) — name, description, engine
25
- (default "claude_code"), trigger type (schedule/ticket_label/manual/
26
- webhook — schedule additionally asks for a cron string, ticket_label
27
- for a label), and the standing prompt text. Writes
28
- ~/.agentos/agents/<name>.yaml and registers it with the backend.
29
- agentos agent add <path>
30
- Validate a hand-written manifest YAML, store a copy under
31
- ~/.agentos/agents/<name>.yaml (if not already there), and register
32
- it with the backend.
23
+ agentos agent create --name NAME (--prompt TEXT | --prompt-file PATH)
24
+ [--var NAME[:LABEL[:TYPE[:DESCRIPTION]]]]… [--secret NAME[:DESCRIPTION]]…
25
+ [--skill ID]…
26
+ agentos agent create --from-file PATH
27
+ Create a custom agent through the AI backend (POST /api/v1/agents/custom),
28
+ which evaluates it — a rejection prints the reasons and score — and
29
+ forwards it to the platform; the SDK never writes a DB. PATH holds one JSON body
30
+ ({name, prompt:{system_prompt, variables}, skills, secrets, media}) or
31
+ {"agents": [...]} to create many; names you already own are skipped.
32
+ Secrets are NAMES only. Without --var, the {{placeholders}} in the prompt
33
+ become the variables. See sdk.custom_agents — the Custom Agents page of
34
+ the control panel uses the same code.
35
+ agentos agent update NAME_OR_ID [--name NAME] [--prompt[-file] …] [--var …]…
36
+ [--secret …]… [--skill ID]… [--status active|inactive|disabled] [--from-file PATH]
37
+ PATCH /api/v1/agents/custom/{name or id} with only the given fields.
38
+ --var / --secret / --skill each REPLACE that whole list. Your own agents
39
+ only — the backend answers "not found" for anything else, department
40
+ agents included.
41
+ agentos agent delete NAME_OR_ID [--yes]
42
+ Show the agent and, after a y/N confirmation (skipped by --yes), delete it
43
+ on the platform (DELETE /api/v1/agents/custom/{name or id}), then forget its local copy
44
+ and stored keys. Cannot be undone.
33
45
  agentos agent list
34
46
  Show local (personal) agents (name, engine, trigger type), merged
35
47
  with backend status when the backend is reachable, PLUS this user's
@@ -47,22 +59,25 @@ Command surface:
47
59
  agentos agent enable <name> / agentos agent disable <name>
48
60
  Flip the agent's backend status to "active" / "disabled".
49
61
  agentos agent rm <name>
50
- De-register the agent from the backend and delete its local manifest.
62
+ Remove the agent from THIS machine (local manifest, stored API keys, last
63
+ inputs) and best-effort de-register it by name on the AI backend. To
64
+ delete the agent itself on the platform, use `agentos agent delete`.
51
65
 
52
66
  agentos ticket create --project KEY --summary TEXT [--type T] [--priority P]
53
67
  [--assignee EMAIL] [--description[-file] …] [--instructions[-file] …]
54
68
  [--parent ID] [--status S] [--points N]
55
- File one ticket (POST /tasks-ml) and print its Jira key. Type defaults to
56
- Task, priority to Medium, assignee to the token owner. Validated locally
57
- first; a gateway rejection prints the gateway's own messages.
69
+ File one ticket (POST /api/v1/tasks on the AI backend) and print its Jira
70
+ key. Type defaults to Task, priority to Medium, assignee to the token
71
+ owner (server-side). Validated locally first; a rejection prints the
72
+ backend's own messages.
58
73
  agentos ticket update KEY_OR_ID [--summary …] [--description[-file] …]
59
74
  [--instructions[-file] …] [--priority P] [--status S] [--points N]
60
75
  [--assignee EMAIL] [--type T]
61
- Change only the given fields (PUT /tasks-ml/{id}). Takes a Jira key or
76
+ Change only the given fields (PATCH /api/v1/tasks/{id}). Takes a Jira key or
62
77
  the platform id. See sdk.tickets — the Tickets page uses the same code.
63
78
  agentos ticket delete KEY_OR_ID [--yes]
64
79
  Show the ticket and, after a y/N confirmation (skipped by --yes), delete it
65
- (DELETE /tasks-ml/{id}). Cannot be undone.
80
+ (DELETE /api/v1/tasks/{id}). Cannot be undone.
66
81
 
67
82
  agentos integration add <path>
68
83
  Register an integration (MCP server, etc.) from a JSON file.
@@ -226,6 +241,7 @@ def _print_usage() -> None:
226
241
  print(" agentos configure [--rotate]")
227
242
  print(" agentos chat [--product-id ID] [--pv-id ID] [--no-autorun] # requirements → ticket")
228
243
  print(" agentos agent <list|run NAME|chat NAME MSG|logs NAME|enable NAME|disable NAME|rm NAME>")
244
+ print(" agentos agent <create [flags]|update NAME_OR_ID [flags]|delete NAME_OR_ID [--yes]|help> # custom-agent CRUD")
229
245
  print(" agentos agent <set-key NAME KEY[=VALUE]…|keys NAME|rm-key NAME KEY…> # persistent API keys (custom agents)")
230
246
  print(" agentos ticket <create|update KEY_OR_ID|delete KEY_OR_ID|help>")
231
247
  print(" agentos integration <add PATH|test NAME|list|rm NAME>")
@@ -246,13 +262,18 @@ def _agent_command(args: list[str]) -> None:
246
262
  verb = args[0] if args else None
247
263
  rest = args[1:]
248
264
 
249
- # Agent CREATION (`new` / `add`) is not owned by the SDK anymore — agents are
250
- # authored in the web app and written to the backend `agents` table. The CLI is
251
- # consume-only: list / run / chat / logs / enable / disable / rm / keys.
265
+ # Create / update / delete go through the AI backend's /api/v1/agents/custom (the SDK
266
+ # never writes a DB) — see sdk.custom_agents. The old local-manifest wizard
267
+ # (`new` / `add PATH`) stays gone; point at the replacement.
252
268
  if verb in ("new", "add"):
253
- print("`agentos agent new/add` has been removed — agents are created in the "
254
- "web app now. Use `agentos agent list` to see yours and `agentos agent "
255
- "run <name>` to run one.")
269
+ print(f"`agentos agent {verb}` has been replaced by `agentos agent create` "
270
+ "(flags or --from-file PATH). See `agentos agent help`.")
271
+ sys.exit(1)
272
+ if verb in ("help", "-h", "--help"):
273
+ _agent_crud_usage()
274
+ sys.exit(0)
275
+ if verb in ("create", "update", "delete"):
276
+ _agent_crud_command(verb, rest)
256
277
  return
257
278
  if verb == "list":
258
279
  _agent_list()
@@ -288,7 +309,7 @@ def _agent_command(args: list[str]) -> None:
288
309
  _agent_rm_key(rest[0], rest[1:])
289
310
  return
290
311
 
291
- print("usage: agentos agent <new|add PATH|list|run NAME|run-ticket NAME [--ticket KEY] "
312
+ print("usage: agentos agent <create|update NAME_OR_ID|delete NAME_OR_ID|help|list|run NAME|run-ticket NAME [--ticket KEY] "
292
313
  "[--var k=v]… [--secret K=V]… [--scope department --department-id UUID]|chat NAME MESSAGE|"
293
314
  "template [NAME]|logs NAME|enable NAME|disable NAME|rm NAME|set-key NAME KEY[=VALUE]…|"
294
315
  "keys NAME|rm-key NAME KEY…>")
@@ -506,21 +527,311 @@ def _agent_enable_disable(name: str, enable: bool) -> None:
506
527
 
507
528
 
508
529
  def _agent_rm(name: str) -> None:
530
+ from sdk.client import BackendClient
531
+
532
+ asyncio.run(BackendClient.from_config().delete_custom_agent(name))
533
+ if _agent_forget_local(name):
534
+ print(f"removed '{name}' (and its stored API keys)")
535
+ else:
536
+ print(f"removed '{name}'")
537
+
538
+
539
+ def _agent_forget_local(name: str) -> bool:
540
+ """Drop this machine's copy of an agent: manifest, last-used variables and
541
+ stored API keys. True when stored keys were removed."""
509
542
  from sdk.agents import secrets as agent_secrets
510
543
  from sdk.agents import varstore as agent_varstore
511
544
  from sdk.agents.manifest import AGENTS_DIR
512
- from sdk.client import BackendClient
513
545
 
514
- asyncio.run(BackendClient.from_config().delete_custom_agent(name))
515
546
  path = AGENTS_DIR / f"{name}.yaml"
516
547
  if path.exists():
517
548
  path.unlink()
518
- # Remove the agent's persisted API keys + last-used variables too.
519
549
  agent_varstore.delete_vars(name)
520
- if agent_secrets.delete_all(name):
521
- print(f"removed '{name}' (and its stored API keys)")
550
+ return bool(agent_secrets.delete_all(name))
551
+
552
+
553
+ # ── agent create / update / delete (AI backend /api/v1/agents/custom) ────
554
+
555
+ # Flags that take one value. Repeatable list flags are collected separately.
556
+ _AGENT_VALUE_FLAGS = {"--name", "--prompt", "--prompt-file", "--status", "--from-file"}
557
+ _AGENT_LIST_FLAGS = {"--var", "--secret", "--skill"}
558
+ _AGENT_UPDATE_ONLY = {"--status"}
559
+
560
+
561
+ def _agent_crud_usage() -> None:
562
+ print("usage: agentos agent <create|update NAME_OR_ID|delete NAME_OR_ID|help>")
563
+ print()
564
+ print(" agentos agent create --name NAME (--prompt TEXT | --prompt-file PATH)")
565
+ print(" [--var NAME[:LABEL[:TYPE[:DESCRIPTION]]]]… [--secret NAME[:DESCRIPTION]]… [--skill ID]…")
566
+ print(" agentos agent create --from-file PATH # one JSON body, or {\"agents\": [...]} (existing names skipped)")
567
+ print(" agentos agent update NAME_OR_ID [--name NAME] [--prompt TEXT | --prompt-file PATH]")
568
+ print(" [--var …]… [--secret …]… [--skill ID]… [--status active|inactive|disabled] [--from-file PATH]")
569
+ print(" agentos agent delete NAME_OR_ID [--yes] # asks to confirm unless --yes")
570
+ print()
571
+ print(" Use {{name}} in the prompt for inputs; without --var they are derived from the prompt.")
572
+ print(" Secrets are NAMES only (e.g. --secret GITHUB_TOKEN:\"repo access\"); values stay on")
573
+ print(" your machine (`agentos agent set-key`). On update, --var/--secret/--skill replace the list.")
574
+ print(" Only your own agents can be changed; department agents are read-only (\"not found\").")
575
+ print(" A create the backend's evaluation rejects prints `rejected: <reasons> (score N)`.")
576
+ print(" `agentos agent rm NAME` only removes this machine's copy — `delete` removes the agent.")
577
+
578
+
579
+ def _parse_var_flag(value: str) -> dict:
580
+ parts = value.split(":", 3)
581
+ parts += [""] * (4 - len(parts))
582
+ name, label, vtype, desc = (p.strip() for p in parts)
583
+ out = {"name": name, "label": label or name, "description": desc}
584
+ out["type"] = vtype or "text"
585
+ return out
586
+
587
+
588
+ def _parse_secret_flag(value: str) -> dict:
589
+ name, _, desc = value.partition(":")
590
+ return {"name": name.strip(), "description": desc.strip()}
591
+
592
+
593
+ def _read_text_file(flag: str, value: str) -> str:
594
+ path = Path(value).expanduser()
595
+ try:
596
+ return path.read_text(encoding="utf-8")
597
+ except OSError as exc:
598
+ print(f"error: {flag}: cannot read {path}: {exc.strerror or exc}")
599
+ sys.exit(1)
600
+
601
+
602
+ def _parse_agent_flags(args: list[str], *, creating: bool) -> tuple[dict, str | None]:
603
+ """Flags → (wire payload, --from-file path). Exits 1 on an unknown flag, a
604
+ missing value, a value flag given twice, or an unreadable file."""
605
+ verb = "create" if creating else "update"
606
+ single: dict[str, str] = {}
607
+ lists: dict[str, list[str]] = {}
608
+ i = 0
609
+ while i < len(args):
610
+ flag = args[i]
611
+ known = flag in _AGENT_VALUE_FLAGS or flag in _AGENT_LIST_FLAGS
612
+ if not known or (creating and flag in _AGENT_UPDATE_ONLY):
613
+ print(f"error: unknown option for `agentos agent {verb}`: {flag}")
614
+ sys.exit(1)
615
+ if i + 1 >= len(args):
616
+ print(f"error: expected a value after {flag}")
617
+ sys.exit(1)
618
+ value = args[i + 1]
619
+ if flag in _AGENT_LIST_FLAGS:
620
+ lists.setdefault(flag, []).append(value)
621
+ else:
622
+ if flag in single:
623
+ print(f"error: pass {flag} once")
624
+ sys.exit(1)
625
+ single[flag] = value
626
+ i += 2
627
+ if "--prompt" in single and "--prompt-file" in single:
628
+ print("error: pass --prompt or --prompt-file, not both")
629
+ sys.exit(1)
630
+
631
+ payload: dict = {}
632
+ if "--name" in single:
633
+ payload["name"] = single["--name"]
634
+ prompt_text = single.get("--prompt")
635
+ if "--prompt-file" in single:
636
+ prompt_text = _read_text_file("--prompt-file", single["--prompt-file"])
637
+ prompt: dict = {}
638
+ if prompt_text is not None:
639
+ prompt["system_prompt"] = prompt_text
640
+ if "--var" in lists:
641
+ prompt["variables"] = [_parse_var_flag(v) for v in lists["--var"]]
642
+ if prompt:
643
+ payload["prompt"] = prompt
644
+ for v in lists.get("--secret", []):
645
+ if "=" in v:
646
+ print(f"error: --secret {v.split('=', 1)[0]}=…: secrets are NAMES only — never "
647
+ "pass a value. Store it on this machine with `agentos agent set-key`.")
648
+ sys.exit(1)
649
+ if "--secret" in lists:
650
+ payload["secrets"] = [_parse_secret_flag(v) for v in lists["--secret"]]
651
+ if "--skill" in lists:
652
+ payload["skills"] = list(lists["--skill"])
653
+ if "--status" in single:
654
+ payload["status"] = single["--status"]
655
+ return payload, single.get("--from-file")
656
+
657
+
658
+ def _load_agent_file(path_str: str) -> list[dict] | dict:
659
+ """--from-file → one body (dict) or many (list, from {"agents": [...]})."""
660
+ import json
661
+
662
+ raw = _read_text_file("--from-file", path_str)
663
+ try:
664
+ data = json.loads(raw)
665
+ except ValueError as exc:
666
+ print(f"error: --from-file: {path_str} is not valid JSON: {exc}")
667
+ sys.exit(1)
668
+ if isinstance(data, dict) and "agents" in data:
669
+ agents = data["agents"]
670
+ if not isinstance(agents, list) or not all(isinstance(a, dict) for a in agents):
671
+ print('error: --from-file: "agents" must be a list of agent objects')
672
+ sys.exit(1)
673
+ return agents
674
+ if isinstance(data, list):
675
+ if not all(isinstance(a, dict) for a in data):
676
+ print("error: --from-file: every entry must be an agent object")
677
+ sys.exit(1)
678
+ return data
679
+ if not isinstance(data, dict):
680
+ print("error: --from-file: expected a JSON object")
681
+ sys.exit(1)
682
+ return data
683
+
684
+
685
+ def _merge_payload(base: dict, over: dict) -> dict:
686
+ """Flags win over the file; a partial flag prompt merges into the file's prompt."""
687
+ out = {**base, **{k: v for k, v in over.items() if k != "prompt"}}
688
+ if "prompt" in over:
689
+ file_prompt = base.get("prompt") if isinstance(base.get("prompt"), dict) else {}
690
+ if isinstance(base.get("prompt"), str):
691
+ file_prompt = {"system_prompt": base["prompt"]}
692
+ out["prompt"] = {**file_prompt, **over["prompt"]}
693
+ return out
694
+
695
+
696
+ def _print_warnings(res: dict) -> None:
697
+ for w in res.get("warnings") or []:
698
+ print(f"warning: {w}")
699
+
700
+
701
+ def _agent_crud_command(verb: str, args: list[str]) -> None:
702
+ """`agentos agent create|update|delete` — see sdk.custom_agents for the rules."""
703
+ if verb in {"update", "delete"} and (not args or args[0].startswith("--")):
704
+ _agent_crud_usage()
705
+ sys.exit(1)
706
+ if verb == "delete":
707
+ _agent_crud_delete(args[0], args[1:])
708
+ return
709
+
710
+ from sdk import custom_agents
711
+ from sdk.client import BackendClient
712
+
713
+ creating = verb == "create"
714
+ flag_args = args if creating else args[1:]
715
+ payload, from_file = _parse_agent_flags(flag_args, creating=creating)
716
+ many: list[dict] | None = None
717
+ if from_file:
718
+ loaded = _load_agent_file(from_file)
719
+ if isinstance(loaded, list):
720
+ if not creating:
721
+ print("error: --from-file with several agents is for `create` only")
722
+ sys.exit(1)
723
+ if payload:
724
+ print("error: a bulk --from-file cannot be combined with other flags")
725
+ sys.exit(1)
726
+ many = loaded
727
+ else:
728
+ loaded.pop("id", None)
729
+ payload = _merge_payload(loaded, payload)
730
+
731
+ if many is not None:
732
+ # Validate every entry before building a client, so a bad file never needs a token.
733
+ for n, item in enumerate(many, 1):
734
+ _, err, _ = custom_agents.build_body(item, creating=True)
735
+ if err:
736
+ print(f"error: agent #{n} ({item.get('name') or 'unnamed'}): {err}")
737
+ sys.exit(1)
738
+ client = BackendClient.from_config()
739
+ results = asyncio.run(custom_agents.create_many(client, many))
740
+ created = skipped = failed = 0
741
+ for res in results:
742
+ if res.get("skipped"):
743
+ skipped += 1
744
+ print(f"skipped {res['name']} (already exists)")
745
+ elif res["ok"]:
746
+ created += 1
747
+ print(f"created {res['name']} (id {res['id']})")
748
+ _print_warnings(res)
749
+ else:
750
+ failed += 1
751
+ print(f"error: {res.get('name') or ''}: {res['error']}".replace("error: : ", "error: "))
752
+ print(f"{created} created, {skipped} skipped, {failed} failed")
753
+ sys.exit(1 if failed else 0)
754
+
755
+ if creating:
756
+ if not payload.get("name") or not (
757
+ isinstance(payload.get("prompt"), (dict, str)) and payload.get("prompt")):
758
+ print("error: --name and --prompt (or --prompt-file / --from-file) are required")
759
+ sys.exit(1)
760
+ elif not payload:
761
+ print("error: nothing to update: pass at least one field")
762
+ _agent_crud_usage()
763
+ sys.exit(1)
764
+ # Validate before building a client, so a bad flag never needs a token.
765
+ if creating:
766
+ _, err, _ = custom_agents.build_body(payload, creating=True)
522
767
  else:
523
- print(f"removed '{name}'")
768
+ err = custom_agents.precheck_update(payload)
769
+ if err:
770
+ print(f"error: {err}")
771
+ sys.exit(1)
772
+
773
+ client = BackendClient.from_config()
774
+ if creating:
775
+ res = asyncio.run(custom_agents.create_agent(client, payload))
776
+ else:
777
+ res = asyncio.run(custom_agents.update_agent(client, args[0], payload))
778
+ _print_warnings(res)
779
+ if not res["ok"]:
780
+ print(f"error: {res['error']}")
781
+ sys.exit(1)
782
+ if creating:
783
+ print(f"created {res['name']} (id {res['id'] or 'unknown'})")
784
+ ev = res.get("evaluation") or {}
785
+ if isinstance(ev, dict) and ev.get("score") is not None:
786
+ print(f"evaluation: accepted, score {ev['score']}")
787
+ else:
788
+ print(f"updated {res['name']}: {', '.join(res.get('fields') or sorted(payload))}")
789
+ sys.exit(0)
790
+
791
+
792
+ def _agent_crud_delete(target: str, flags: list[str]) -> None:
793
+ """`agentos agent delete NAME_OR_ID [--yes]` — shows the agent, then asks."""
794
+ from sdk import custom_agents
795
+ from sdk.client import BackendClient
796
+
797
+ unknown = [f for f in flags if f not in {"--yes", "-y"}]
798
+ if unknown:
799
+ print(f"error: unknown option for `agentos agent delete`: {unknown[0]}")
800
+ sys.exit(1)
801
+ client = BackendClient.from_config()
802
+ rec: dict | None = None
803
+ name = target
804
+ if not flags:
805
+ # Show what is about to go. The server is the authority on "is it yours",
806
+ # so only a definite "not found" stops here.
807
+ rec, err = asyncio.run(custom_agents.get_agent(client, target))
808
+ if rec is None and err.startswith("agent not found"):
809
+ print(f"error: {err}")
810
+ sys.exit(1)
811
+ if rec is not None:
812
+ name = rec["name"] or rec["id"]
813
+ first = (rec["prompt"]["system_prompt"].strip().splitlines() or [""])[0][:100]
814
+ print(f"{name} (id {rec['id']}) [{rec.get('status') or '?'}] {first}")
815
+ try:
816
+ answer = input(f"Delete agent {name}? This cannot be undone. [y/N] ")
817
+ except EOFError:
818
+ answer = ""
819
+ if answer.strip().lower() not in {"y", "yes"}:
820
+ print("not deleted")
821
+ sys.exit(1)
822
+ res = asyncio.run(custom_agents.delete_agent(client, rec["id"] if rec else target))
823
+ if not res["ok"]:
824
+ print(f"error: {res['error']}")
825
+ sys.exit(1)
826
+ local_name = (rec or {}).get("name") or target
827
+ if local_name:
828
+ try:
829
+ _agent_forget_local(local_name)
830
+ except Exception as exc: # noqa: BLE001 — the platform delete already happened
831
+ print(f"warning: deleted on the platform, but this machine's copy was not "
832
+ f"cleaned up ({exc}); run `agentos agent rm {local_name}`")
833
+ print(f"deleted {name}")
834
+ sys.exit(0)
524
835
 
525
836
 
526
837
  def _agent_exists(name: str) -> bool:
@@ -542,7 +853,7 @@ def _agent_set_key(name: str, pairs: list[str]) -> None:
542
853
 
543
854
  if not _agent_exists(name):
544
855
  print(f"error: no local agent named '{name}'. Install it first "
545
- f"(agentos agent add / default-agents activate).")
856
+ f"(`agentos agent list` shows what this machine has; create one with `agentos agent create`).")
546
857
  sys.exit(1)
547
858
 
548
859
  updates: dict[str, str] = {}
@@ -645,7 +956,7 @@ def _pop_department_id(args: list[str]) -> tuple[str | None, list[str]]:
645
956
  return dept_id, out
646
957
 
647
958
 
648
- # `agentos ticket` flag → POST/PUT /tasks-ml wire name. Text flags have a
959
+ # `agentos ticket` flag → POST/PATCH /api/v1/tasks wire name. Text flags have a
649
960
  # `-file` twin that reads the value from a file instead.
650
961
  _TICKET_FLAGS = {
651
962
  "--project": "projectKey", "--type": "type", "--summary": "summary",
@@ -655,7 +966,7 @@ _TICKET_FLAGS = {
655
966
  }
656
967
  _TICKET_FILE_FLAGS = {"--description-file": "--description",
657
968
  "--instructions-file": "--instructions"}
658
- # Create-only: neither is editable through PUT /tasks-ml/{id}.
969
+ # Create-only: neither is editable through PATCH /api/v1/tasks/{id}.
659
970
  _TICKET_CREATE_ONLY = {"--project", "--parent"}
660
971
 
661
972
 
@@ -830,7 +1141,7 @@ def _require_department_manager(verb: str) -> None:
830
1141
  f"activate department agents, but only department managers (team_lead+) "
831
1142
  f"can '{verb}' them.")
832
1143
  print("note: your own custom agents are unrestricted — use `agentos agent "
833
- "<new|add|enable|disable|rm> …`.")
1144
+ "<create|update|delete|enable|disable|rm> …`.")
834
1145
  sys.exit(1)
835
1146
 
836
1147