devops-bot-sdk 1.7.20__tar.gz → 1.7.36__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.7.20 → devops_bot_sdk-1.7.36}/PKG-INFO +3 -1
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/PKG-INFO +3 -1
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/SOURCES.txt +8 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/requires.txt +3 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/pyproject.toml +6 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agentd.py +35 -12
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/schedules.py +56 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/cli.py +14 -9
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/config.py +3 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/faqs.py +33 -1
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/git_ops.py +73 -14
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/graph_recon.py +4 -1
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/graphify.py +17 -3
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/helpdesk_kb.md +101 -3
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ipc/handlers.py +106 -16
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/log_colors.py +20 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/run_auto.py +48 -3
- devops_bot_sdk-1.7.36/sdk/schedule_timeline.py +171 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ticket_pools.py +88 -6
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/api.py +18 -2
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/dashboard.py +34 -9
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/models.py +2 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/agents.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/app.js +897 -110
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/chat.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/custom-agents.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/default-agents.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/faqs.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/help.html +6 -5
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/index.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/report.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/runs.html +2 -1
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/schedules.html +34 -13
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/setup.html +1 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/styles.css +309 -4
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/static/tickets.html +100 -26
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_run_ticket.py +62 -0
- devops_bot_sdk-1.7.36/tests/test_graph_off_by_default.py +27 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_graph_recon.py +6 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_graphify_build.py +6 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_graphify_hook_install.py +6 -0
- devops_bot_sdk-1.7.36/tests/test_pool_pr_modes.py +143 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_prd_artifact.py +6 -0
- devops_bot_sdk-1.7.36/tests/test_quiet_run_log.py +40 -0
- devops_bot_sdk-1.7.36/tests/test_schedule_timeline.py +115 -0
- devops_bot_sdk-1.7.36/tests/test_theme_switch.py +35 -0
- devops_bot_sdk-1.7.36/tests/test_ticket_detail_view.py +51 -0
- devops_bot_sdk-1.7.36/tests/test_ui_no_native_dialogs.py +18 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/README.md +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/classifier.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/collectors/common.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/collectors/linux_auditd.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/collectors/macos_eslogger.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/collectors/windows_eventlog.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/models.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/os_setup.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/recorder.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/redact.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/settings.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/shipper.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/activity/spool.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agent_sharing.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/activity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/ticket_run.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/browser_profile.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/claude_usage.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/client.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/custom_agents.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/deferred_tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/departments.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/estimator.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/fallback_handoff.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/firewall.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/formats.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/github_fetch.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/github_ingest.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/help_actions.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/helpdesk.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/instructions_template.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/intake.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/journal.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/memory_guard.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/model_policy.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/phase_timer.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/plan_run.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/prd_progress.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/proof_readers.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/providers.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/resume.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/router.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/schedule_tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/scheduler.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/scope_plan.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/self_report.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/self_report_local.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/swagger.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/task_file.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/task_types.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/test.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ticket_board.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ticket_bulk.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ticket_fields.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ticket_plan.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/tiers/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/tiers/mini_agent.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/service.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/session.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/ui/swagger.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/url_access.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/vps_health.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/vps_identity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/sdk/write_hook.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/setup.cfg +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_claude_runs.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_collectors.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_core.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_live_tracking.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_macos.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_os_setup.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_activity_pipeline.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_activity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_activity_tracking.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_crud_cli.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_listing.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_prompt_async.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_schedules.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_sharing.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agent_workspace_settings.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_allowed_tools_config.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_approval_park.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_auto_agent_dispatch.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_auto_ticket_queue.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_browser_profile.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_cheap_tier.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_claude_usage_gate.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_client_jira_projects.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_config_token_diagnostics.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_configure_token_owner.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_console_encoding.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_crash_recovery.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_create_safe_retry.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_deferred_tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_departments.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_done_transition.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_epic_decompose_run.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_epic_inherited_agent_id.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_epic_session_isolation.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_estimator.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_fallback_cli.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_fallback_cli_upgrade.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_faqs.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_firewall_open_on_update.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_formats.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_github_fetch.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_github_ingest.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_help_actions.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_help_attachments.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_help_questions.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_helpdesk.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_infographic_data.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_instructions_template.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_intake_job_outcome.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_intake_plan_review.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_journal.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_limit_fallback_handoff.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_local_exec_provider.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_log_colors_backlog.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_mcp_route_contract.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_memory_guard.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_model_policy.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_panel_help.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_panel_ticket_schedules.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_parallel_tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_phase_timer.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_plan_new_command.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_plan_run_activity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_pr_identity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_project_path_resolution.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_proof_readers.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_providers.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_recon_session_isolation.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_resume.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_router.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_run_auto_agent_only.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_run_outputs.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_run_verdict_is_honest.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_schedule_api.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_schedule_outputs_and_plans.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_schedule_tickets.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_scheduler.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_scheduler_transient_retry.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_self_report.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_service_token_warning.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_stale_panel_restart.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_swagger_command.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_task_file_and_plan_run.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_task_file_format_doc.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_board.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_bulk.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_cli.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_fields.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_plan.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_pools.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_run_resolve_by_id.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_schedule_and_agent.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ticket_speed_fixes.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_tier_flag_parity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ui_gate.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_ui_lifespan.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_update_timer.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_updater_extras.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_updater_ignores_cwd.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_updater_pep668.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_updater_reports_the_truth.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_url_access.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_vps_health.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_vps_only_reporting.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_windows_loop_identity.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_windows_panel_task.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_windows_stop_and_pidfile.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/tests/test_windows_task_paths.py +0 -0
- {devops_bot_sdk-1.7.20 → devops_bot_sdk-1.7.36}/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.
|
|
3
|
+
Version: 1.7.36
|
|
4
4
|
Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
|
|
5
5
|
Author: noumanaziz2128
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -22,6 +22,8 @@ Requires-Dist: fastapi>=0.110; extra == "ui"
|
|
|
22
22
|
Requires-Dist: uvicorn>=0.29; extra == "ui"
|
|
23
23
|
Requires-Dist: psutil>=5.9; extra == "ui"
|
|
24
24
|
Requires-Dist: python-multipart>=0.0.9; extra == "ui"
|
|
25
|
+
Provides-Extra: ui-e2e
|
|
26
|
+
Requires-Dist: playwright>=1.45; extra == "ui-e2e"
|
|
25
27
|
Provides-Extra: all
|
|
26
28
|
Requires-Dist: Pillow>=10.0; extra == "all"
|
|
27
29
|
Requires-Dist: psutil>=5.9; extra == "all"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devops-bot-sdk
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.36
|
|
4
4
|
Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
|
|
5
5
|
Author: noumanaziz2128
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -22,6 +22,8 @@ Requires-Dist: fastapi>=0.110; extra == "ui"
|
|
|
22
22
|
Requires-Dist: uvicorn>=0.29; extra == "ui"
|
|
23
23
|
Requires-Dist: psutil>=5.9; extra == "ui"
|
|
24
24
|
Requires-Dist: python-multipart>=0.0.9; extra == "ui"
|
|
25
|
+
Provides-Extra: ui-e2e
|
|
26
|
+
Requires-Dist: playwright>=1.45; extra == "ui-e2e"
|
|
25
27
|
Provides-Extra: all
|
|
26
28
|
Requires-Dist: Pillow>=10.0; extra == "all"
|
|
27
29
|
Requires-Dist: psutil>=5.9; extra == "all"
|
|
@@ -50,6 +50,7 @@ sdk/resume.py
|
|
|
50
50
|
sdk/router.py
|
|
51
51
|
sdk/run_auto.py
|
|
52
52
|
sdk/schedule_tickets.py
|
|
53
|
+
sdk/schedule_timeline.py
|
|
53
54
|
sdk/scheduler.py
|
|
54
55
|
sdk/scope_plan.py
|
|
55
56
|
sdk/self_report.py
|
|
@@ -206,6 +207,7 @@ tests/test_formats.py
|
|
|
206
207
|
tests/test_git_action.py
|
|
207
208
|
tests/test_github_fetch.py
|
|
208
209
|
tests/test_github_ingest.py
|
|
210
|
+
tests/test_graph_off_by_default.py
|
|
209
211
|
tests/test_graph_recon.py
|
|
210
212
|
tests/test_graphify_build.py
|
|
211
213
|
tests/test_graphify_hook_install.py
|
|
@@ -231,11 +233,13 @@ tests/test_parallel_tickets.py
|
|
|
231
233
|
tests/test_phase_timer.py
|
|
232
234
|
tests/test_plan_new_command.py
|
|
233
235
|
tests/test_plan_run_activity.py
|
|
236
|
+
tests/test_pool_pr_modes.py
|
|
234
237
|
tests/test_pr_identity.py
|
|
235
238
|
tests/test_prd_artifact.py
|
|
236
239
|
tests/test_project_path_resolution.py
|
|
237
240
|
tests/test_proof_readers.py
|
|
238
241
|
tests/test_providers.py
|
|
242
|
+
tests/test_quiet_run_log.py
|
|
239
243
|
tests/test_recon_session_isolation.py
|
|
240
244
|
tests/test_resume.py
|
|
241
245
|
tests/test_router.py
|
|
@@ -245,6 +249,7 @@ tests/test_run_verdict_is_honest.py
|
|
|
245
249
|
tests/test_schedule_api.py
|
|
246
250
|
tests/test_schedule_outputs_and_plans.py
|
|
247
251
|
tests/test_schedule_tickets.py
|
|
252
|
+
tests/test_schedule_timeline.py
|
|
248
253
|
tests/test_scheduler.py
|
|
249
254
|
tests/test_scheduler_transient_retry.py
|
|
250
255
|
tests/test_self_report.py
|
|
@@ -253,9 +258,11 @@ tests/test_stale_panel_restart.py
|
|
|
253
258
|
tests/test_swagger_command.py
|
|
254
259
|
tests/test_task_file_and_plan_run.py
|
|
255
260
|
tests/test_task_file_format_doc.py
|
|
261
|
+
tests/test_theme_switch.py
|
|
256
262
|
tests/test_ticket_board.py
|
|
257
263
|
tests/test_ticket_bulk.py
|
|
258
264
|
tests/test_ticket_cli.py
|
|
265
|
+
tests/test_ticket_detail_view.py
|
|
259
266
|
tests/test_ticket_fields.py
|
|
260
267
|
tests/test_ticket_plan.py
|
|
261
268
|
tests/test_ticket_pools.py
|
|
@@ -265,6 +272,7 @@ tests/test_ticket_speed_fixes.py
|
|
|
265
272
|
tests/test_tier_flag_parity.py
|
|
266
273
|
tests/test_ui_gate.py
|
|
267
274
|
tests/test_ui_lifespan.py
|
|
275
|
+
tests/test_ui_no_native_dialogs.py
|
|
268
276
|
tests/test_update_timer.py
|
|
269
277
|
tests/test_updater_extras.py
|
|
270
278
|
tests/test_updater_ignores_cwd.py
|
|
@@ -41,6 +41,9 @@ ui = [
|
|
|
41
41
|
# raises at request time without it, so it belongs in [ui]
|
|
42
42
|
# alongside fastapi rather than in an optional extra.
|
|
43
43
|
]
|
|
44
|
+
ui-e2e = [
|
|
45
|
+
"playwright>=1.45", # tests/ui_e2e — headless-Chromium panel tests (then: python -m playwright install chromium)
|
|
46
|
+
]
|
|
44
47
|
all = [
|
|
45
48
|
"Pillow>=10.0",
|
|
46
49
|
"psutil>=5.9",
|
|
@@ -60,6 +63,9 @@ agentos-swagger = "sdk.swagger:main" # where /docs is + can you reach it
|
|
|
60
63
|
Homepage = "https://agentos.io"
|
|
61
64
|
Repository = "https://github.com/consultancy-outfit/DevOpsBot-SDK"
|
|
62
65
|
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
markers = ["ui_e2e: headless-Chromium control-panel tests (need the ui-e2e extra; skipped without it)"]
|
|
68
|
+
|
|
63
69
|
[tool.setuptools.dynamic]
|
|
64
70
|
version = { attr = "sdk.__version__" } # bump sdk/__init__.py → wheel + client + server all follow
|
|
65
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.36
|
|
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.
|
|
37
|
+
__version__ = "1.7.36" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
38
38
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
39
39
|
|
|
40
40
|
from sdk.client import BackendClient
|
|
@@ -359,21 +359,41 @@ async def _dispatch_agent_run(
|
|
|
359
359
|
manifest.integrations, available, env=secret_env,
|
|
360
360
|
)
|
|
361
361
|
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
|
|
362
|
+
# {{variables}}, most specific first: explicit run-time values (UI/API/CLI) win
|
|
363
|
+
# over the attached ticket's fields, which win over the values last saved for
|
|
364
|
+
# this agent (sdk/agents/varstore.py — what the panel's Run used). Nothing here
|
|
365
|
+
# is persisted. A person-started run (auto_approve) that would still leave a
|
|
366
|
+
# placeholder unfilled is REFUSED up front: the agent cannot do the work, so it
|
|
367
|
+
# would only spend a run asking for the values (ticket-instructions-writer,
|
|
368
|
+
# 2026-10-27, got literal {{ticket_key}} / {{repos_root}}).
|
|
369
|
+
from sdk.agents import varstore as agent_varstore
|
|
370
|
+
|
|
367
371
|
names = extract_variables(manifest.prompt)
|
|
368
|
-
|
|
369
|
-
|
|
372
|
+
used_inputs: dict[str, str] = {}
|
|
373
|
+
if names:
|
|
374
|
+
saved = {k: v for k, v in agent_varstore.load_vars(manifest.name).items()
|
|
375
|
+
if k in names and str(v).strip()}
|
|
376
|
+
values = dict(saved)
|
|
377
|
+
if task:
|
|
378
|
+
values.update({k: v for k, v in values_from_ticket(names, task).items() if str(v).strip()})
|
|
370
379
|
if extra_variables:
|
|
371
|
-
values
|
|
380
|
+
values.update({k: str(v) for k, v in extra_variables.items() if str(v).strip()})
|
|
372
381
|
resolved_prompt, missing = substitute_variables(manifest.prompt, values)
|
|
373
|
-
if
|
|
382
|
+
used_inputs = {k: v for k, v in values.items() if k in names}
|
|
383
|
+
if missing and auto_approve:
|
|
384
|
+
outcome["status"] = "missing_inputs"
|
|
385
|
+
outcome["missing"] = missing
|
|
386
|
+
outcome["error"] = (
|
|
387
|
+
f"'{manifest.name}' needs {', '.join(missing)} — fill "
|
|
388
|
+
f"{'it' if len(missing) == 1 else 'them'} in, or pick a ticket that has "
|
|
389
|
+
f"{'it' if len(missing) == 1 else 'them'}. Nothing was run."
|
|
390
|
+
)
|
|
391
|
+
logger.info("agentd.missing_inputs agent=%s missing=%s", manifest.name, missing)
|
|
392
|
+
return outcome
|
|
393
|
+
if used_inputs:
|
|
374
394
|
logger.info(
|
|
375
|
-
"agentd.vars_filled agent=%s filled=%s missing=%s",
|
|
376
|
-
manifest.name, sorted(
|
|
395
|
+
"agentd.vars_filled agent=%s filled=%s from_saved=%s missing=%s",
|
|
396
|
+
manifest.name, sorted(used_inputs), sorted(saved), sorted(missing),
|
|
377
397
|
)
|
|
378
398
|
manifest = manifest.model_copy(update={"prompt": resolved_prompt})
|
|
379
399
|
|
|
@@ -455,9 +475,12 @@ async def _dispatch_agent_run(
|
|
|
455
475
|
from sdk.agents.engines import claude_code as claude_code_engine
|
|
456
476
|
from sdk.agents import run_log
|
|
457
477
|
|
|
458
|
-
|
|
478
|
+
# A person pressed Run (auto_approve) → "run"; only an unattended
|
|
479
|
+
# trigger without a ticket is "scheduled".
|
|
480
|
+
_kind = "ticket" if task else ("run" if auto_approve else "scheduled")
|
|
459
481
|
_log_path = run_log.start_run(
|
|
460
482
|
manifest.name, scope="custom", engine=manifest.engine, kind=_kind,
|
|
483
|
+
variables=used_inputs or None,
|
|
461
484
|
)
|
|
462
485
|
run_log.log_line(_log_path, f"task_id={task_id}")
|
|
463
486
|
|
|
@@ -411,6 +411,7 @@ def mark_result(schedule_id: str, *, ok: bool, status: str = "",
|
|
|
411
411
|
if schedule is None:
|
|
412
412
|
return None
|
|
413
413
|
schedule["last_status"] = status or ("ok" if ok else "failed")
|
|
414
|
+
_append_history(schedule, ok=ok, output_file=output_file)
|
|
414
415
|
if output_file:
|
|
415
416
|
schedule["last_output_file"] = output_file
|
|
416
417
|
if delivered_to:
|
|
@@ -431,6 +432,61 @@ def mark_result(schedule_id: str, *, ok: bool, status: str = "",
|
|
|
431
432
|
return schedule
|
|
432
433
|
|
|
433
434
|
|
|
435
|
+
# Every outcome mark_result records, one JSON line each, so the Schedules page can
|
|
436
|
+
# show what ran before the latest run. Not ``*.json``: list_schedules globs those.
|
|
437
|
+
HISTORY_NAME = "history.jsonl"
|
|
438
|
+
HISTORY_MAX_LINES = 5000
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def history_path() -> Path:
|
|
442
|
+
return SCHEDULES_DIR / HISTORY_NAME
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _append_history(schedule: dict, *, ok: bool, output_file: str = "") -> None:
|
|
446
|
+
"""Best-effort: a history failure never affects the run or the schedule."""
|
|
447
|
+
row = {
|
|
448
|
+
"at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
449
|
+
"fired_at": schedule.get("last_fire_at") or "",
|
|
450
|
+
"schedule_id": schedule.get("schedule_id") or "",
|
|
451
|
+
"agent": schedule.get("agent") or "",
|
|
452
|
+
"kind": schedule.get("kind") or "agent",
|
|
453
|
+
"ok": bool(ok),
|
|
454
|
+
"status": schedule.get("last_status") or "",
|
|
455
|
+
"output_file": output_file or "",
|
|
456
|
+
}
|
|
457
|
+
try:
|
|
458
|
+
path = history_path()
|
|
459
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
460
|
+
with path.open("a", encoding="utf-8") as fh:
|
|
461
|
+
fh.write(json.dumps(row, ensure_ascii=False) + "\n")
|
|
462
|
+
if path.stat().st_size > HISTORY_MAX_LINES * 400: # trim rarely, keep the newest
|
|
463
|
+
lines = path.read_text(encoding="utf-8").splitlines()[-HISTORY_MAX_LINES:]
|
|
464
|
+
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
465
|
+
except OSError as exc:
|
|
466
|
+
logger.debug("schedules.history_write_failed err=%s", exc)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def read_history(since: datetime | None = None) -> list[dict]:
|
|
470
|
+
"""Recorded outcomes, oldest first (optionally only those at/after ``since``)."""
|
|
471
|
+
out: list[dict] = []
|
|
472
|
+
try:
|
|
473
|
+
lines = history_path().read_text(encoding="utf-8").splitlines()
|
|
474
|
+
except OSError:
|
|
475
|
+
return out
|
|
476
|
+
for line in lines:
|
|
477
|
+
try:
|
|
478
|
+
row = json.loads(line)
|
|
479
|
+
except ValueError:
|
|
480
|
+
continue
|
|
481
|
+
if not isinstance(row, dict):
|
|
482
|
+
continue
|
|
483
|
+
at = _parse_iso(row.get("fired_at")) or _parse_iso(row.get("at"))
|
|
484
|
+
if at is None or (since is not None and at < since):
|
|
485
|
+
continue
|
|
486
|
+
out.append(row)
|
|
487
|
+
return out
|
|
488
|
+
|
|
489
|
+
|
|
434
490
|
def for_agent(agent: str) -> list[dict]:
|
|
435
491
|
return [s for s in list_schedules() if s.get("agent") == agent]
|
|
436
492
|
|
|
@@ -1264,12 +1264,12 @@ _POOL_USAGE = """usage: agentos pool <command> — up to 50 tickets you run to
|
|
|
1264
1264
|
|
|
1265
1265
|
agentos pool list # every pool, its size and last run
|
|
1266
1266
|
agentos pool show NAME # run order, each ticket's summary/status, instructions
|
|
1267
|
-
agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] # new pool (keys in run order)
|
|
1267
|
+
agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] [--pr-mode per_ticket|stacked|single] # new pool (keys in run order)
|
|
1268
1268
|
agentos pool add NAME KEY… [--at POS] # add tickets (at the end, or at position POS)
|
|
1269
1269
|
agentos pool remove NAME KEY… # take tickets out
|
|
1270
1270
|
agentos pool move NAME KEY POS # move one ticket to position POS (1 = first)
|
|
1271
1271
|
agentos pool order NAME KEY… # these first, in this order; the rest follow
|
|
1272
|
-
agentos pool set NAME [--instructions TEXT | --clear-instructions] [--parallel N] [--rename NEW]
|
|
1272
|
+
agentos pool set NAME [--instructions TEXT | --clear-instructions] [--parallel N] [--pr-mode MODE] [--rename NEW]
|
|
1273
1273
|
agentos pool run NAME [--parallel N] # run it now (= agentos-auto pool NAME)
|
|
1274
1274
|
agentos pool delete NAME # remove the pool (tickets are untouched)
|
|
1275
1275
|
|
|
@@ -1306,8 +1306,11 @@ def _pool_opts(args: list[str], valued: tuple[str, ...], bare: tuple[str, ...] =
|
|
|
1306
1306
|
|
|
1307
1307
|
def _pool_print(pool: dict, info: dict | None = None) -> None:
|
|
1308
1308
|
from sdk import log_colors
|
|
1309
|
+
from sdk.ticket_pools import PR_MODE_LABELS as TP_LABELS
|
|
1309
1310
|
paint = log_colors.colorize if log_colors.enabled() else (lambda x: x)
|
|
1310
|
-
|
|
1311
|
+
mode = pool.get("pr_mode") or "per_ticket"
|
|
1312
|
+
at_once = f"up to {pool.get('parallel')} at once" if mode == "per_ticket" else "one at a time"
|
|
1313
|
+
print(f"pool {pool['name']} — {len(pool['keys'])} ticket(s), {at_once}, {TP_LABELS.get(mode, mode)}"
|
|
1311
1314
|
+ (f", last run {pool['last_run_at']}" if pool.get("last_run_at") else ""))
|
|
1312
1315
|
width = max(len(k) for k in pool["keys"]) if pool["keys"] else 0
|
|
1313
1316
|
for n, k in enumerate(pool["keys"], 1):
|
|
@@ -1358,11 +1361,13 @@ def _pool_command(args: list[str]) -> None:
|
|
|
1358
1361
|
_pool_print(pool, info)
|
|
1359
1362
|
return
|
|
1360
1363
|
if sub == "create":
|
|
1361
|
-
pos, opts = _pool_opts(rest, ("--instructions", "--parallel"))
|
|
1364
|
+
pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--pr-mode"))
|
|
1362
1365
|
if len(pos) < 2:
|
|
1363
|
-
print("usage: agentos pool create NAME KEY… [--instructions TEXT] [--parallel N]"
|
|
1366
|
+
print("usage: agentos pool create NAME KEY… [--instructions TEXT] [--parallel N] "
|
|
1367
|
+
"[--pr-mode per_ticket|stacked|single]")
|
|
1364
1368
|
sys.exit(1)
|
|
1365
|
-
pool = TP.create(pos[0], pos[1:], opts.get("--instructions", ""), _parallel(opts)
|
|
1369
|
+
pool = TP.create(pos[0], pos[1:], opts.get("--instructions", ""), _parallel(opts),
|
|
1370
|
+
opts.get("--pr-mode"))
|
|
1366
1371
|
shown = f'"{pool["name"]}"' if " " in pool["name"] else pool["name"]
|
|
1367
1372
|
print(f"✓ created pool {pool['name']} with {len(pool['keys'])} ticket(s) — "
|
|
1368
1373
|
f"run it: agentos pool run {shown}")
|
|
@@ -1389,15 +1394,15 @@ def _pool_command(args: list[str]) -> None:
|
|
|
1389
1394
|
sys.exit(1)
|
|
1390
1395
|
pool = TP.order(rest[0], rest[1:])
|
|
1391
1396
|
elif sub == "set":
|
|
1392
|
-
pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--rename"),
|
|
1397
|
+
pos, opts = _pool_opts(rest, ("--instructions", "--parallel", "--rename", "--pr-mode"),
|
|
1393
1398
|
("--clear-instructions",))
|
|
1394
1399
|
if len(pos) != 1 or not opts:
|
|
1395
1400
|
print("usage: agentos pool set NAME [--instructions TEXT | --clear-instructions] "
|
|
1396
|
-
"[--parallel N] [--rename NEW]")
|
|
1401
|
+
"[--parallel N] [--pr-mode per_ticket|stacked|single] [--rename NEW]")
|
|
1397
1402
|
sys.exit(1)
|
|
1398
1403
|
instr = "" if opts.get("--clear-instructions") else opts.get("--instructions")
|
|
1399
1404
|
pool = TP.update(pos[0], instructions=instr, parallel=_parallel(opts),
|
|
1400
|
-
rename=opts.get("--rename"))
|
|
1405
|
+
rename=opts.get("--rename"), pr_mode=opts.get("--pr-mode"))
|
|
1401
1406
|
elif sub == "delete":
|
|
1402
1407
|
if not rest:
|
|
1403
1408
|
print("usage: agentos pool delete NAME")
|
|
@@ -407,6 +407,9 @@ FLAG_TIERED_ROUTING = "AGENTOS_TIERED_ROUTING"
|
|
|
407
407
|
FLAG_JOURNAL = "AGENTOS_JOURNAL"
|
|
408
408
|
#: Write the generated PRD to ``docs/prd/<KEY>.md`` in the repo.
|
|
409
409
|
FLAG_PRD_FILE = "AGENTOS_PRD_FILE"
|
|
410
|
+
#: The knowledge graph (graphify + graph recon). OFF by default since 1.7.27;
|
|
411
|
+
#: ``AGENTOS_GRAPHIFY=1`` (env or config.toml) turns it back on.
|
|
412
|
+
FLAG_GRAPHIFY = "AGENTOS_GRAPHIFY"
|
|
410
413
|
#: Supervise ``graphify watch`` instead of relying on the debounce.
|
|
411
414
|
FLAG_GRAPH_WATCH = "AGENTOS_GRAPHIFY_WATCH"
|
|
412
415
|
#: Cheap-tier mini agent (sdk/tiers/). Requires backend reachability.
|
|
@@ -7,7 +7,25 @@ FAQS: list[tuple[str, str, str]] = [
|
|
|
7
7
|
("Basics", "Does my code leave my machine?",
|
|
8
8
|
"No. The server plans and gates; cloning, coding, commits and PRs run locally with claude."),
|
|
9
9
|
("Basics", "What do I need before installing?",
|
|
10
|
-
"
|
|
10
|
+
"Tick every line:\n"
|
|
11
|
+
"1. **Python 3.11+** — `python3 --version`\n"
|
|
12
|
+
"2. **git** — `git --version`\n"
|
|
13
|
+
"3. **GitHub over SSH** — your SSH key on your GitHub account; `ssh -T git@github.com` greets you by name\n"
|
|
14
|
+
"4. **Added to the repositories** — read on DevOpsBot-SDK (to install and update it), write on every repo "
|
|
15
|
+
"your tickets work on, each cloned where its Human Instructions say\n"
|
|
16
|
+
"5. **A way to open PRs** — the platform's GitHub token, or `gh auth login`\n"
|
|
17
|
+
"6. **The claude CLI, logged in** — `claude setup-token`; no claude? the AI Draftsman CLI: "
|
|
18
|
+
"`agentos fallback install`, then `agentos fallback login`\n"
|
|
19
|
+
"7. **Your co_ API token** — `agentos configure`\n"
|
|
20
|
+
"Then `agentos doctor` checks the lot."),
|
|
21
|
+
("Basics", "Can I run tickets without the claude CLI?",
|
|
22
|
+
"Yes. Install and log in the AI Draftsman CLI (agentos fallback install, agentos fallback login --browser; "
|
|
23
|
+
"check with agentos fallback status --verify). The loop refuses to start only when neither claude nor ad "
|
|
24
|
+
"is ready; with both, ad takes over whenever claude is missing, logged out or out of usage."),
|
|
25
|
+
("Basics", "Cloning, pushing or opening PRs fails. What do I check?",
|
|
26
|
+
"ssh -T git@github.com must greet you by name (add your SSH key to GitHub if not); you must be added to the "
|
|
27
|
+
"repo with write access; gh auth status must be logged in unless the platform gives the SDK a GitHub token. "
|
|
28
|
+
"A repo whose origin is not on GitHub gets its branch pushed but no PR, so the ticket goes to Backlog."),
|
|
11
29
|
("Updates", "How does the SDK stay up to date?",
|
|
12
30
|
"Every machine checks for a new version every 6 hours by itself — a systemd timer on Linux, a "
|
|
13
31
|
"Task Scheduler task on Windows, a launchd agent on macOS — and catches up after downtime. "
|
|
@@ -55,6 +73,20 @@ FAQS: list[tuple[str, str, str]] = [
|
|
|
55
73
|
"A very old console refuses colour mode, or NO_COLOR is set. Try AGENTOS_COLOR=always."),
|
|
56
74
|
("Help", "Where do settings and logs live?",
|
|
57
75
|
"~/.agentos: config.toml, auto.log, pools, schedules and per-run logs. agentos doctor bundles them for an admin."),
|
|
76
|
+
("Tickets", "How do I move tickets between statuses?",
|
|
77
|
+
"Any status can move to any other. On the Tickets page tick them and press Move to ▾, change Status in "
|
|
78
|
+
"a ticket's side panel, or drag cards on the Board tab. From the CLI: agentos ticket bulk-update KEY… --status Done."),
|
|
79
|
+
("Plans & pools", "Can pooled tickets build on each other, or share one PR?",
|
|
80
|
+
"Yes — the pool's PR mode: agentos pool set NAME --pr-mode stacked (each ticket branches from the previous "
|
|
81
|
+
"one and its PR targets it) or --pr-mode single (one branch and one PR for the whole pool). Both run one "
|
|
82
|
+
"ticket at a time, in pool order."),
|
|
83
|
+
("Agents", "Why did my agent say \"Not run — fill in …\"?",
|
|
84
|
+
"Its prompt needs inputs that had no value — not in the form, not on the picked ticket, and not saved from "
|
|
85
|
+
"its last run. Nothing was run and nothing was spent. Fill the inputs or pick a ticket."),
|
|
86
|
+
("Running work", "The log shows only a few lines while a ticket runs. Is it stuck?",
|
|
87
|
+
"No — the log shows each file edited and one progress line a minute, and \"still working … quiet for Nm\" "
|
|
88
|
+
"during long silent steps such as a test run. Every step is in the ticket's claude log; "
|
|
89
|
+
"AGENTOS_VERBOSE_STEPS=1 brings them back. agentos-auto status shows the current ticket."),
|
|
58
90
|
]
|
|
59
91
|
|
|
60
92
|
|
|
@@ -80,9 +80,9 @@ _TICKET_BRANCH_RE = re.compile(r"^[A-Za-z][A-Za-z0-9]{1,9}-\d+$")
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def _is_work_branch(name: str) -> bool:
|
|
83
|
-
"""True when `name` is one of OUR generated work branches (feature
|
|
84
|
-
bare ticket id) — i.e. never a legitimate base."""
|
|
85
|
-
return name.startswith("feature/") or bool(_TICKET_BRANCH_RE.match(name))
|
|
83
|
+
"""True when `name` is one of OUR generated work branches (feature/*, a pool's
|
|
84
|
+
pool/* or a bare ticket id) — i.e. never a legitimate base."""
|
|
85
|
+
return name.startswith(("feature/", "pool/")) or bool(_TICKET_BRANCH_RE.match(name))
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
async def detect_default_branch(path: str, env: dict) -> str:
|
|
@@ -163,9 +163,16 @@ async def start_branch(
|
|
|
163
163
|
github_token: str | None,
|
|
164
164
|
base: str | None = None,
|
|
165
165
|
branch_name: str | None = None,
|
|
166
|
+
continue_branch: bool = False,
|
|
166
167
|
) -> dict | None:
|
|
167
168
|
"""Create + check out a feature branch off the resolved base.
|
|
168
169
|
|
|
170
|
+
``continue_branch`` (a one-PR ticket pool, after its first ticket): check out
|
|
171
|
+
the EXISTING ``branch_name`` as it stands — local, else ``origin/`` — and bring
|
|
172
|
+
it up to date, instead of re-cutting it from ``base``; ``base`` is returned
|
|
173
|
+
unchanged so the PR keeps its target. Re-cutting would throw away the earlier
|
|
174
|
+
tickets' commits.
|
|
175
|
+
|
|
169
176
|
Branch name:
|
|
170
177
|
- `branch_name` given (an explicit name parsed from the Jira
|
|
171
178
|
humanInstructions or a configured template, e.g. the exact ticket id
|
|
@@ -196,6 +203,17 @@ async def start_branch(
|
|
|
196
203
|
return None
|
|
197
204
|
|
|
198
205
|
explicit_name = (branch_name or "").strip().lstrip("/")
|
|
206
|
+
if continue_branch and explicit_name:
|
|
207
|
+
await _run(["git", "fetch", "origin"], path, env, timeout=180.0)
|
|
208
|
+
rc, _, _ = await _run(["git", "checkout", explicit_name], path, env)
|
|
209
|
+
if rc != 0:
|
|
210
|
+
rc, _, _ = await _run(["git", "checkout", "-B", explicit_name, f"origin/{explicit_name}"], path, env)
|
|
211
|
+
if rc == 0:
|
|
212
|
+
await _run(["git", "pull", "--ff-only", "origin", explicit_name], path, env, timeout=120.0)
|
|
213
|
+
pr_base = (base or "").strip() or await detect_default_branch(path, env)
|
|
214
|
+
logger.info("git_ops.branch | %s continued (pool), PR base %s", explicit_name, pr_base)
|
|
215
|
+
return {"branch": explicit_name, "base": pr_base}
|
|
216
|
+
# Not there yet (the pool's first ticket): cut it like any named branch.
|
|
199
217
|
if explicit_name:
|
|
200
218
|
# Honour the exact name the human/convention asked for (e.g. "CD-72").
|
|
201
219
|
branch = explicit_name
|
|
@@ -212,15 +230,20 @@ async def start_branch(
|
|
|
212
230
|
# local ref of that name, then to a bare branch, if the remote lacks it.
|
|
213
231
|
await _run(["git", "fetch", "origin", explicit], path, env, timeout=120.0)
|
|
214
232
|
resolved = "main" if explicit == branch else explicit
|
|
215
|
-
|
|
216
|
-
if
|
|
217
|
-
|
|
218
|
-
|
|
233
|
+
refs = [r for r in (f"origin/{resolved}", resolved) if await _ref_exists(path, env, r)]
|
|
234
|
+
if not refs:
|
|
235
|
+
# The base does not exist anywhere (a typo, or a brand-new repo): cut
|
|
236
|
+
# from HEAD, and say which branch that really is.
|
|
219
237
|
rc, _, _ = await _run(["git", "checkout", "-B", branch], path, env)
|
|
220
|
-
|
|
238
|
+
if rc != 0:
|
|
239
|
+
return None
|
|
240
|
+
logger.warning("git_ops.branch | base %s not found — %s cut from the current checkout", resolved, branch)
|
|
241
|
+
return {"branch": branch, "base": resolved, "note": f"base {resolved} not found — cut from the current checkout"}
|
|
242
|
+
info = await _checkout_from(path, env, branch, refs)
|
|
243
|
+
if info is None:
|
|
221
244
|
return None
|
|
222
245
|
logger.info("git_ops.branch | %s ← explicit base %s", branch, resolved)
|
|
223
|
-
return {"branch": branch, "base": resolved}
|
|
246
|
+
return {"branch": branch, "base": resolved, **info}
|
|
224
247
|
|
|
225
248
|
# Default: base = the CURRENT checked-out branch (the user's working branch).
|
|
226
249
|
rc, cur, _ = await _run(["git", "rev-parse", "--abbrev-ref", "HEAD"], path, env)
|
|
@@ -238,13 +261,49 @@ async def start_branch(
|
|
|
238
261
|
resolved = await detect_default_branch(path, env)
|
|
239
262
|
if resolved == branch:
|
|
240
263
|
resolved = "main"
|
|
241
|
-
|
|
242
|
-
if
|
|
243
|
-
|
|
244
|
-
|
|
264
|
+
refs = [r for r in (f"origin/{resolved}", resolved) if await _ref_exists(path, env, r)]
|
|
265
|
+
info = await _checkout_from(path, env, branch, refs) if refs else None
|
|
266
|
+
if info is None:
|
|
267
|
+
# Never fall back to the stale work branch that is checked out: that is
|
|
268
|
+
# how one ticket's half-finished changes end up in the next one's PR.
|
|
269
|
+
logger.warning("git_ops.branch | %s: could not cut from %s (HEAD was %r)", branch, resolved, cur or "detached")
|
|
245
270
|
return None
|
|
246
271
|
logger.info("git_ops.branch | %s ← default base %s (HEAD was %r)", branch, resolved, cur or "detached")
|
|
247
|
-
return {"branch": branch, "base": resolved}
|
|
272
|
+
return {"branch": branch, "base": resolved, **info}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
async def _ref_exists(path: str, env: dict, ref: str) -> bool:
|
|
276
|
+
rc, _, _ = await _run(["git", "rev-parse", "--verify", "--quiet", ref + "^{commit}"], path, env)
|
|
277
|
+
return rc == 0
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
async def _checkout_from(path: str, env: dict, branch: str, refs: list[str]) -> dict | None:
|
|
281
|
+
"""Check ``branch`` out fresh from the first of ``refs`` that works → {} or
|
|
282
|
+
{"stashed": msg}; None when none does.
|
|
283
|
+
|
|
284
|
+
The usual reason a checkout fails is uncommitted changes in the way —
|
|
285
|
+
typically a previous ticket's half-finished work. Those are STASHED (kept, with
|
|
286
|
+
a message naming this branch; ``git stash list`` shows them) and the checkout
|
|
287
|
+
retried, instead of quietly cutting the branch from whatever is checked out —
|
|
288
|
+
which would carry those changes, and a stale codebase, into this ticket's PR.
|
|
289
|
+
"""
|
|
290
|
+
for ref in refs:
|
|
291
|
+
rc, _, _ = await _run(["git", "checkout", "-B", branch, ref], path, env)
|
|
292
|
+
if rc == 0:
|
|
293
|
+
return {}
|
|
294
|
+
if not await has_local_changes(path):
|
|
295
|
+
return None
|
|
296
|
+
msg = f"agentos: uncommitted changes set aside before {branch}"
|
|
297
|
+
rc, _, err = await _run(["git", "stash", "push", "--include-untracked", "-m", msg], path, env)
|
|
298
|
+
if rc != 0:
|
|
299
|
+
logger.warning("git_ops.stash_failed %s: %s", branch, err[:200])
|
|
300
|
+
return None
|
|
301
|
+
logger.warning("git_ops.branch | stashed uncommitted changes before %s", branch)
|
|
302
|
+
for ref in refs:
|
|
303
|
+
rc, _, _ = await _run(["git", "checkout", "-B", branch, ref], path, env)
|
|
304
|
+
if rc == 0:
|
|
305
|
+
return {"stashed": msg}
|
|
306
|
+
return None
|
|
248
307
|
|
|
249
308
|
|
|
250
309
|
async def _remote_owner_repo(path: str, env: dict) -> tuple[str, str] | None:
|
|
@@ -75,7 +75,10 @@ _CAMEL_RE = re.compile(r"[A-Z]+(?![a-z])|[A-Z][a-z0-9]*|[a-z0-9]+")
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
def _disabled() -> bool:
|
|
78
|
-
|
|
78
|
+
if os.getenv("AGENTOS_NO_GRAPH_RECON"):
|
|
79
|
+
return True
|
|
80
|
+
from sdk import graphify # no graph (off by default) → no graph recon
|
|
81
|
+
return not graphify.enabled()
|
|
79
82
|
|
|
80
83
|
|
|
81
84
|
def _split_identifier(word: str) -> list[str]:
|
|
@@ -6,8 +6,11 @@ hook**, so the agent queries the graph instead of loading whole files — keepin
|
|
|
6
6
|
large projects inside the context window.
|
|
7
7
|
|
|
8
8
|
Everything here is best-effort and never raises: if graphify is unavailable or a
|
|
9
|
-
step fails, the run continues on plain `claude`.
|
|
10
|
-
|
|
9
|
+
step fails, the run continues on plain `claude`.
|
|
10
|
+
|
|
11
|
+
OFF by default (1.7.27): nothing is installed, built or queried unless
|
|
12
|
+
``AGENTOS_GRAPHIFY=1`` is set (environment or ``config.toml``). The code stays so
|
|
13
|
+
it can be switched back on; ``AGENTOS_NO_GRAPHIFY=1`` still forces it off.
|
|
11
14
|
|
|
12
15
|
Per-project flow (called once before each local `claude` run):
|
|
13
16
|
ensure_installed() → auto-install `graphifyy` via uv → pipx → pip if missing
|
|
@@ -45,8 +48,19 @@ _SKILL_MARKER = _AGENTOS_DIR / ".graphify_skill_installed"
|
|
|
45
48
|
_STATE_FILE = _AGENTOS_DIR / "graphify_state.json"
|
|
46
49
|
|
|
47
50
|
|
|
51
|
+
def enabled() -> bool:
|
|
52
|
+
"""True only when switched on (``AGENTOS_GRAPHIFY=1``) and not forced off."""
|
|
53
|
+
if os.getenv("AGENTOS_NO_GRAPHIFY"):
|
|
54
|
+
return False
|
|
55
|
+
try:
|
|
56
|
+
from sdk import config
|
|
57
|
+
return config.flag(config.FLAG_GRAPHIFY)
|
|
58
|
+
except Exception: # noqa: BLE001 — a config hiccup leaves it off
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
48
62
|
def _disabled() -> bool:
|
|
49
|
-
return
|
|
63
|
+
return not enabled()
|
|
50
64
|
|
|
51
65
|
|
|
52
66
|
def is_available() -> bool:
|