devops-bot-sdk 1.6.66__tar.gz → 1.6.68__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.
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/SOURCES.txt +1 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/service.py +94 -22
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_update_timer.py +2 -0
- devops_bot_sdk-1.6.68/tests/test_windows_task_paths.py +172 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/README.md +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/pyproject.toml +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/classifier.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/collectors/common.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/collectors/linux_auditd.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/collectors/macos_eslogger.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/collectors/windows_eventlog.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/models.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/os_setup.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/recorder.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/redact.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/settings.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/shipper.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/activity/spool.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/activity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/schedules.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/ticket_run.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/browser_profile.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/client.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/config.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/custom_agents.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/departments.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/estimator.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/firewall.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/formats.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/github_fetch.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/github_ingest.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/graph_recon.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/intake.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/journal.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/memory_guard.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/phase_timer.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/plan_run.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/prd_progress.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/proof_readers.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/providers.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/resume.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/router.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/scheduler.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/self_report.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/self_report_local.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/swagger.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/task_file.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/task_types.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/test.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/tickets.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/tiers/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/tiers/mini_agent.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/api.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/models.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/session.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/app.js +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/chat.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/custom-agents.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/report.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/schedules.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/ui/swagger.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/url_access.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/vendor/aidraftsman-cli-0.1.0.tgz +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/vps_health.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/sdk/write_hook.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/setup.cfg +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_activity_collectors.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_activity_core.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_activity_macos.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_activity_os_setup.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_activity_pipeline.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_activity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_activity_tracking.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_crud_cli.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_listing.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_prompt_async.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_run_ticket.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_schedules.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agent_workspace_settings.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_allowed_tools_config.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_auto_agent_dispatch.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_browser_profile.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_cheap_tier.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_client_jira_projects.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_config_token_diagnostics.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_configure_token_owner.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_console_encoding.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_crash_recovery.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_departments.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_done_transition.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_epic_decompose_run.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_epic_inherited_agent_id.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_epic_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_estimator.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_fallback_cli.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_firewall_open_on_update.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_formats.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_github_fetch.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_github_ingest.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_graph_recon.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_graphify_build.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_graphify_hook_install.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_intake_job_outcome.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_intake_plan_review.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_journal.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_local_exec_provider.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_mcp_route_contract.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_memory_guard.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_phase_timer.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_plan_new_command.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_plan_run_activity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_pr_identity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_prd_artifact.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_project_path_resolution.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_proof_readers.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_providers.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_recon_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_resume.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_router.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_run_auto_agent_only.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_run_outputs.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_run_verdict_is_honest.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_schedule_api.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_schedule_outputs_and_plans.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_scheduler.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_self_report.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_service_token_warning.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_stale_panel_restart.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_swagger_command.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_task_file_and_plan_run.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_task_file_format_doc.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ticket_cli.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ticket_run_resolve_by_id.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ticket_speed_fixes.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_tier_flag_parity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ui_gate.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_ui_lifespan.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_updater_extras.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_updater_pep668.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_updater_reports_the_truth.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_url_access.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_vps_health.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_windows_loop_identity.py +0 -0
- {devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/tests/test_write_hook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.68
|
|
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.
|
|
37
|
+
__version__ = "1.6.68" # 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
|
|
@@ -33,25 +33,65 @@ WIN_TASK = "AgentOS Control Panel" # Windows scheduled-task name
|
|
|
33
33
|
WIN_UPDATE_TASK = "AgentOS Self-Update" # Windows counterpart of agentos-update.timer
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def _script_dirs() -> list[Path]:
|
|
37
|
+
"""Where pip puts console scripts for THIS interpreter, most specific first.
|
|
38
|
+
|
|
39
|
+
Next to the interpreter covers a venv (``bin/`` / ``Scripts\\`` holds both
|
|
40
|
+
``python`` and the scripts). It does NOT cover a regular Windows install, where
|
|
41
|
+
``python.exe`` sits in the install root and the scripts in its ``Scripts\\``
|
|
42
|
+
subfolder — ``sysconfig``'s ``scripts`` path is the one that knows. The user
|
|
43
|
+
scheme covers a ``pip install --user``.
|
|
44
|
+
"""
|
|
45
|
+
import sysconfig
|
|
46
|
+
|
|
47
|
+
dirs = [Path(sys.executable).parent]
|
|
48
|
+
for args in (("scripts",), ("scripts", f"{os.name}_user")):
|
|
49
|
+
try:
|
|
50
|
+
p = sysconfig.get_path(*args)
|
|
51
|
+
except KeyError: # scheme not defined on this platform
|
|
52
|
+
continue
|
|
53
|
+
if p and Path(p) not in dirs:
|
|
54
|
+
dirs.append(Path(p))
|
|
55
|
+
return dirs
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _console_script(base: str) -> str | None:
|
|
59
|
+
"""ABSOLUTE path to this SDK's ``base`` console script, or ``None`` if not found."""
|
|
60
|
+
name = f"{base}.exe" if IS_WINDOWS else base
|
|
61
|
+
for d in _script_dirs():
|
|
62
|
+
cand = d / name
|
|
63
|
+
if cand.exists():
|
|
64
|
+
return str(cand)
|
|
65
|
+
found = shutil.which(name)
|
|
66
|
+
return str(Path(found).resolve()) if found else None
|
|
67
|
+
|
|
68
|
+
|
|
36
69
|
def _exe() -> str:
|
|
37
70
|
"""ABSOLUTE path to the ``agentos-ui`` console script.
|
|
38
71
|
|
|
39
|
-
Must be absolute: a service manager (systemd/launchd) does NOT
|
|
40
|
-
user's PATH
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
Must be absolute: a service manager (systemd/launchd/Task Scheduler) does NOT
|
|
73
|
+
search the user's PATH, so a bare ``agentos-ui`` fails with 203/EXEC when the
|
|
74
|
+
script lives somewhere like ``~/.local/bin`` (a ``pip --user`` install) — the
|
|
75
|
+
common case on a VPS — and with 0x80070002 (file not found) on Windows, where
|
|
76
|
+
it lives in ``<python>\\Scripts``. Resolved via :func:`_console_script`; the
|
|
77
|
+
bare name is a last resort kept so a systemd install never hard-fails. The
|
|
78
|
+
Windows installers refuse it (see :func:`_require_absolute`).
|
|
46
79
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
80
|
+
return _console_script("agentos-ui") or ("agentos-ui.exe" if IS_WINDOWS else "agentos-ui")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _require_absolute(exe: str, task: str) -> str | None:
|
|
84
|
+
"""Refusal message when ``exe`` is not an absolute path, else ``None``.
|
|
85
|
+
|
|
86
|
+
A scheduled task with a bare program name is created without complaint and then
|
|
87
|
+
never starts — Last Result 0x80070002, no panel, no activity trail, nothing on
|
|
88
|
+
screen. Refusing here turns that silence into a message the updater prints.
|
|
89
|
+
"""
|
|
90
|
+
if Path(exe).is_absolute():
|
|
91
|
+
return None
|
|
92
|
+
return (f"not creating task '{task}': could not find {exe} for this Python "
|
|
93
|
+
f"({sys.executable}). Reinstall the SDK with that interpreter and re-run "
|
|
94
|
+
f"`agentos-auto update`.")
|
|
55
95
|
|
|
56
96
|
|
|
57
97
|
def _run(argv: list[str]) -> tuple[int, str]:
|
|
@@ -169,10 +209,7 @@ def _auto_exe() -> str:
|
|
|
169
209
|
minimal environment, and picking up a different venv's console script is how
|
|
170
210
|
an updater ends up upgrading the wrong installation.
|
|
171
211
|
"""
|
|
172
|
-
|
|
173
|
-
if candidate.exists():
|
|
174
|
-
return str(candidate)
|
|
175
|
-
return shutil.which("agentos-auto") or "agentos-auto"
|
|
212
|
+
return _console_script("agentos-auto") or ("agentos-auto.exe" if IS_WINDOWS else "agentos-auto")
|
|
176
213
|
|
|
177
214
|
|
|
178
215
|
def update_timer_installed() -> bool:
|
|
@@ -374,7 +411,11 @@ def _uninstall_launchd() -> tuple[bool, str]:
|
|
|
374
411
|
# ── Windows (Scheduled Task) ────────────────────────────────────────────────
|
|
375
412
|
|
|
376
413
|
def _install_schtask(host: str, port: int) -> tuple[bool, str]:
|
|
377
|
-
|
|
414
|
+
exe = _exe()
|
|
415
|
+
refusal = _require_absolute(exe, WIN_TASK)
|
|
416
|
+
if refusal:
|
|
417
|
+
return False, refusal
|
|
418
|
+
tr = f'"{exe}" --host {host} --port {port} --no-browser'
|
|
378
419
|
rc, out = _run(["schtasks", "/Create", "/TN", WIN_TASK, "/TR", tr,
|
|
379
420
|
"/SC", "ONLOGON", "/RL", "HIGHEST", "/F"])
|
|
380
421
|
if rc != 0:
|
|
@@ -440,7 +481,11 @@ def _install_update_schtask() -> tuple[bool, str]:
|
|
|
440
481
|
"""
|
|
441
482
|
import tempfile
|
|
442
483
|
|
|
443
|
-
|
|
484
|
+
exe = _auto_exe()
|
|
485
|
+
refusal = _require_absolute(exe, WIN_UPDATE_TASK)
|
|
486
|
+
if refusal:
|
|
487
|
+
return False, refusal
|
|
488
|
+
xml = _update_task_xml(exe, str(Path.home()))
|
|
444
489
|
fd, path = tempfile.mkstemp(suffix=".xml")
|
|
445
490
|
try:
|
|
446
491
|
with os.fdopen(fd, "w", encoding="utf-16") as fh: # schtasks /XML wants UTF-16
|
|
@@ -459,6 +504,29 @@ def _install_update_schtask() -> tuple[bool, str]:
|
|
|
459
504
|
f"daily, randomized, catches up after downtime")
|
|
460
505
|
|
|
461
506
|
|
|
507
|
+
def _schtask_command(task: str) -> str | None:
|
|
508
|
+
"""The program ``task`` runs, from its XML definition; ``None`` if unreadable."""
|
|
509
|
+
import html
|
|
510
|
+
|
|
511
|
+
rc, out = _run(["schtasks", "/Query", "/TN", task, "/XML"])
|
|
512
|
+
if rc != 0:
|
|
513
|
+
return None
|
|
514
|
+
m = re.search(r"<Command>(.*?)</Command>", out, re.S)
|
|
515
|
+
return html.unescape(m.group(1)).strip().strip('"') if m else None
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _schtask_points_nowhere(task: str) -> bool:
|
|
519
|
+
"""True when ``task`` exists but runs a program that is not an existing file.
|
|
520
|
+
|
|
521
|
+
Boxes installed before :func:`_script_dirs` existed have a panel task whose
|
|
522
|
+
program is the bare ``agentos-ui.exe``. It shows "Ready", never runs, and the
|
|
523
|
+
ordinary update path ("installed + unchanged") only ever re-runs it — so without
|
|
524
|
+
this check those boxes would stay broken through every update.
|
|
525
|
+
"""
|
|
526
|
+
cmd = _schtask_command(task)
|
|
527
|
+
return cmd is not None and not (Path(cmd).is_absolute() and Path(cmd).is_file())
|
|
528
|
+
|
|
529
|
+
|
|
462
530
|
def _uninstall_schtask() -> tuple[bool, str]:
|
|
463
531
|
_run(["schtasks", "/Delete", "/TN", WIN_UPDATE_TASK, "/F"])
|
|
464
532
|
_run(["schtasks", "/End", "/TN", WIN_TASK])
|
|
@@ -771,7 +839,7 @@ def ensure(restart_running: bool = False) -> tuple[bool, str]:
|
|
|
771
839
|
if not is_installed():
|
|
772
840
|
ok, msg = install() # create at the current privilege
|
|
773
841
|
return ok, (f"service created — {msg}" if ok else f"could not create service: {msg}")
|
|
774
|
-
if not update_timer_installed():
|
|
842
|
+
if not update_timer_installed() or (IS_WINDOWS and _schtask_points_nowhere(WIN_UPDATE_TASK)):
|
|
775
843
|
_install_update_timer()
|
|
776
844
|
if _needs_root_for_existing():
|
|
777
845
|
return False, ("a system service is installed — run `sudo agentos-ui install` "
|
|
@@ -783,6 +851,10 @@ def ensure(restart_running: bool = False) -> tuple[bool, str]:
|
|
|
783
851
|
if restart_running:
|
|
784
852
|
rok, rmsg = refresh()
|
|
785
853
|
return rok, (_with_token_warning(rmsg) if rok else rmsg)
|
|
854
|
+
if IS_WINDOWS and _schtask_points_nowhere(WIN_TASK):
|
|
855
|
+
rok, rmsg = refresh() # rebuilds the task with an absolute path
|
|
856
|
+
return rok, (_with_token_warning(f"panel task pointed at a missing program — "
|
|
857
|
+
f"rebuilt; {rmsg}") if rok else rmsg)
|
|
786
858
|
if _is_active():
|
|
787
859
|
stale = _restart_if_stale()
|
|
788
860
|
if stale is not None:
|
|
@@ -177,6 +177,7 @@ class TestWindowsUpdateTask:
|
|
|
177
177
|
|
|
178
178
|
def test_creates_the_task_from_a_utf16_xml_file(self, monkeypatch):
|
|
179
179
|
monkeypatch.setattr(service, "IS_WINDOWS", True)
|
|
180
|
+
monkeypatch.setattr(service, "_auto_exe", lambda: "/py/Scripts/agentos-auto.exe")
|
|
180
181
|
seen = {}
|
|
181
182
|
|
|
182
183
|
def fake_run(argv):
|
|
@@ -194,6 +195,7 @@ class TestWindowsUpdateTask:
|
|
|
194
195
|
|
|
195
196
|
def test_a_failed_create_is_reported_not_raised(self, monkeypatch):
|
|
196
197
|
monkeypatch.setattr(service, "IS_WINDOWS", True)
|
|
198
|
+
monkeypatch.setattr(service, "_auto_exe", lambda: "/py/Scripts/agentos-auto.exe")
|
|
197
199
|
monkeypatch.setattr(service, "_run", lambda argv: (1, "Access is denied."))
|
|
198
200
|
ok, msg = service._install_update_timer()
|
|
199
201
|
assert ok is False and "Access is denied." in msg
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Windows scheduled tasks must name their program by ABSOLUTE path.
|
|
2
|
+
|
|
3
|
+
The incident: a Windows VPS on a regular (non-venv) Python install —
|
|
4
|
+
``...\\pythoncore-3.14-64\\python.exe`` with its console scripts in the ``Scripts\\``
|
|
5
|
+
subfolder. ``_exe()`` looked only next to ``python.exe`` and on PATH, found
|
|
6
|
+
neither, and fell back to the bare ``agentos-ui.exe``. ``schtasks /Create``
|
|
7
|
+
accepted that; Task Scheduler does not search PATH, so the panel task sat
|
|
8
|
+
"Ready" with Last Result 0x80070002 (file not found) and never ran — no panel, no
|
|
9
|
+
activity collector, no shipper, so that VPS never sent one activity event. And the
|
|
10
|
+
ordinary update path only re-ran the broken task, so no update ever fixed it.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import sysconfig
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
from sdk.ui import service
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def windows_install(monkeypatch, tmp_path):
|
|
24
|
+
"""A regular Windows install: python.exe in the root, scripts in Scripts\\."""
|
|
25
|
+
root = tmp_path / "pythoncore-3.14-64"
|
|
26
|
+
scripts = root / "Scripts"
|
|
27
|
+
scripts.mkdir(parents=True)
|
|
28
|
+
monkeypatch.setattr(service, "IS_WINDOWS", True)
|
|
29
|
+
monkeypatch.setattr(service.sys, "executable", str(root / "python.exe"))
|
|
30
|
+
monkeypatch.setattr(service.shutil, "which", lambda name: None) # Scripts\ not on PATH
|
|
31
|
+
|
|
32
|
+
def fake_get_path(name, scheme=None):
|
|
33
|
+
if scheme is None:
|
|
34
|
+
return str(scripts)
|
|
35
|
+
raise KeyError(scheme)
|
|
36
|
+
monkeypatch.setattr(sysconfig, "get_path", fake_get_path)
|
|
37
|
+
return scripts
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestResolution:
|
|
41
|
+
def test_finds_the_panel_in_the_scripts_subfolder(self, windows_install):
|
|
42
|
+
(windows_install / "agentos-ui.exe").write_text("")
|
|
43
|
+
assert service._exe() == str(windows_install / "agentos-ui.exe")
|
|
44
|
+
|
|
45
|
+
def test_finds_the_updater_in_the_scripts_subfolder(self, windows_install):
|
|
46
|
+
(windows_install / "agentos-auto.exe").write_text("")
|
|
47
|
+
assert service._auto_exe() == str(windows_install / "agentos-auto.exe")
|
|
48
|
+
|
|
49
|
+
def test_next_to_the_interpreter_still_wins(self, windows_install):
|
|
50
|
+
"""A venv keeps python.exe and the scripts together; that copy is THIS SDK's."""
|
|
51
|
+
beside = Path(service.sys.executable).parent / "agentos-ui.exe"
|
|
52
|
+
beside.write_text("")
|
|
53
|
+
(windows_install / "agentos-ui.exe").write_text("")
|
|
54
|
+
assert service._exe() == str(beside)
|
|
55
|
+
|
|
56
|
+
def test_a_user_scheme_install_is_found(self, monkeypatch, windows_install, tmp_path):
|
|
57
|
+
user_scripts = tmp_path / "Roaming" / "Python" / "Python314" / "Scripts"
|
|
58
|
+
user_scripts.mkdir(parents=True)
|
|
59
|
+
(user_scripts / "agentos-ui.exe").write_text("")
|
|
60
|
+
|
|
61
|
+
def fake_get_path(name, scheme=None):
|
|
62
|
+
return str(user_scripts) if (scheme or "").endswith("_user") else str(windows_install)
|
|
63
|
+
monkeypatch.setattr(sysconfig, "get_path", fake_get_path)
|
|
64
|
+
assert service._exe() == str(user_scripts / "agentos-ui.exe")
|
|
65
|
+
|
|
66
|
+
def test_not_found_anywhere_is_the_bare_name(self, windows_install):
|
|
67
|
+
assert service._exe() == "agentos-ui.exe"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TestRefusesABareProgramName:
|
|
71
|
+
def test_panel_task_is_not_created(self, monkeypatch, windows_install):
|
|
72
|
+
calls = []
|
|
73
|
+
monkeypatch.setattr(service, "_run", lambda argv: (calls.append(argv), (0, ""))[1])
|
|
74
|
+
ok, msg = service._install_schtask("0.0.0.0", 8765)
|
|
75
|
+
assert ok is False
|
|
76
|
+
assert service.WIN_TASK in msg and "agentos-ui.exe" in msg
|
|
77
|
+
assert calls == [] # never reached schtasks /Create
|
|
78
|
+
|
|
79
|
+
def test_update_task_is_not_created(self, monkeypatch, windows_install):
|
|
80
|
+
calls = []
|
|
81
|
+
monkeypatch.setattr(service, "_run", lambda argv: (calls.append(argv), (0, ""))[1])
|
|
82
|
+
ok, msg = service._install_update_schtask()
|
|
83
|
+
assert ok is False and service.WIN_UPDATE_TASK in msg
|
|
84
|
+
assert calls == []
|
|
85
|
+
|
|
86
|
+
def test_panel_task_uses_the_absolute_path_when_found(self, monkeypatch, windows_install):
|
|
87
|
+
exe = windows_install / "agentos-ui.exe"
|
|
88
|
+
exe.write_text("")
|
|
89
|
+
calls = []
|
|
90
|
+
monkeypatch.setattr(service, "_run", lambda argv: (calls.append(argv), (0, ""))[1])
|
|
91
|
+
ok, _ = service._install_schtask("0.0.0.0", 8765)
|
|
92
|
+
assert ok is True
|
|
93
|
+
create = calls[0]
|
|
94
|
+
assert create[:4] == ["schtasks", "/Create", "/TN", service.WIN_TASK]
|
|
95
|
+
assert create[create.index("/TR") + 1].startswith(f'"{exe}" --host 0.0.0.0')
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _task_xml(command: str) -> str:
|
|
99
|
+
return ("<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n<Task><Actions Context=\"Author\">"
|
|
100
|
+
f"<Exec><Command>{command}</Command><Arguments>--host 0.0.0.0</Arguments>"
|
|
101
|
+
"</Exec></Actions></Task>")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TestDetectsABrokenTask:
|
|
105
|
+
def test_a_bare_program_name_points_nowhere(self, monkeypatch):
|
|
106
|
+
monkeypatch.setattr(service, "_run", lambda argv: (0, _task_xml('"agentos-ui.exe"')))
|
|
107
|
+
assert service._schtask_points_nowhere(service.WIN_TASK) is True
|
|
108
|
+
|
|
109
|
+
def test_an_absolute_path_that_no_longer_exists_points_nowhere(self, monkeypatch, tmp_path):
|
|
110
|
+
gone = tmp_path / "old-venv" / "Scripts" / "agentos-ui.exe"
|
|
111
|
+
monkeypatch.setattr(service, "_run", lambda argv: (0, _task_xml(str(gone))))
|
|
112
|
+
assert service._schtask_points_nowhere(service.WIN_TASK) is True
|
|
113
|
+
|
|
114
|
+
def test_an_existing_absolute_path_is_fine(self, monkeypatch, tmp_path):
|
|
115
|
+
exe = tmp_path / "R&D" / "agentos-ui.exe"
|
|
116
|
+
exe.parent.mkdir()
|
|
117
|
+
exe.write_text("")
|
|
118
|
+
escaped = str(exe).replace("&", "&")
|
|
119
|
+
monkeypatch.setattr(service, "_run", lambda argv: (0, _task_xml(f'"{escaped}"')))
|
|
120
|
+
assert service._schtask_points_nowhere(service.WIN_TASK) is False
|
|
121
|
+
|
|
122
|
+
def test_a_task_that_cannot_be_read_is_not_called_broken(self, monkeypatch):
|
|
123
|
+
"""No task, or no permission to read it: not ours to rebuild on a guess."""
|
|
124
|
+
monkeypatch.setattr(service, "_run", lambda argv: (1, "ERROR: cannot find the file"))
|
|
125
|
+
assert service._schtask_points_nowhere(service.WIN_TASK) is False
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TestEnsureRepairsIt:
|
|
129
|
+
@pytest.fixture
|
|
130
|
+
def installed(self, monkeypatch):
|
|
131
|
+
monkeypatch.setattr(service, "IS_WINDOWS", True)
|
|
132
|
+
monkeypatch.setattr(service, "_service_disabled", lambda: False)
|
|
133
|
+
monkeypatch.setattr(service, "is_installed", lambda: True)
|
|
134
|
+
monkeypatch.setattr(service, "update_timer_installed", lambda: True)
|
|
135
|
+
monkeypatch.setattr(service, "_needs_root_for_existing", lambda: False)
|
|
136
|
+
monkeypatch.setattr(service, "_with_token_warning", lambda m: m)
|
|
137
|
+
seen = {"refresh": 0, "timer": 0, "restart": 0}
|
|
138
|
+
|
|
139
|
+
def refresh():
|
|
140
|
+
seen["refresh"] += 1
|
|
141
|
+
return True, "service refreshed"
|
|
142
|
+
|
|
143
|
+
def timer():
|
|
144
|
+
seen["timer"] += 1
|
|
145
|
+
return True, "timer ok"
|
|
146
|
+
|
|
147
|
+
def restart():
|
|
148
|
+
seen["restart"] += 1
|
|
149
|
+
return True, "restarted"
|
|
150
|
+
monkeypatch.setattr(service, "refresh", refresh)
|
|
151
|
+
monkeypatch.setattr(service, "_install_update_timer", timer)
|
|
152
|
+
monkeypatch.setattr(service, "restart", restart)
|
|
153
|
+
monkeypatch.setattr(service, "_is_active", lambda: False)
|
|
154
|
+
return seen
|
|
155
|
+
|
|
156
|
+
def test_a_broken_panel_task_is_rebuilt_without_an_upgrade(self, monkeypatch, installed):
|
|
157
|
+
monkeypatch.setattr(service, "_schtask_points_nowhere", lambda task: task == service.WIN_TASK)
|
|
158
|
+
ok, msg = service.ensure(restart_running=False)
|
|
159
|
+
assert ok is True and "rebuilt" in msg
|
|
160
|
+
assert installed["refresh"] == 1 and installed["restart"] == 0
|
|
161
|
+
|
|
162
|
+
def test_a_broken_update_task_is_recreated(self, monkeypatch, installed):
|
|
163
|
+
monkeypatch.setattr(service, "_schtask_points_nowhere",
|
|
164
|
+
lambda task: task == service.WIN_UPDATE_TASK)
|
|
165
|
+
service.ensure(restart_running=False)
|
|
166
|
+
assert installed["timer"] == 1
|
|
167
|
+
|
|
168
|
+
def test_a_healthy_stopped_task_is_just_started(self, monkeypatch, installed):
|
|
169
|
+
monkeypatch.setattr(service, "_schtask_points_nowhere", lambda task: False)
|
|
170
|
+
service.ensure(restart_running=False)
|
|
171
|
+
assert installed["refresh"] == 0 and installed["timer"] == 0
|
|
172
|
+
assert installed["restart"] == 1
|
|
File without changes
|
{devops_bot_sdk-1.6.66 → devops_bot_sdk-1.6.68}/devops_bot_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|