xdog-coding 2.4.3__tar.gz → 2.4.4__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.
- xdog_coding-2.4.3/README.md → xdog_coding-2.4.4/PKG-INFO +97 -0
- xdog_coding-2.4.3/PKG-INFO → xdog_coding-2.4.4/README.md +65 -32
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/pyproject.toml +5 -5
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/__init__.py +1 -1
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/backend.py +52 -30
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/server.py +33 -18
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/config.py +33 -10
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/agent_session.py +241 -157
- xdog_coding-2.4.4/src/xdog/coding/core/command_names.py +19 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/goal_adapter.py +19 -15
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/resource_loader.py +46 -26
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sdk.py +35 -57
- xdog_coding-2.4.4/src/xdog/coding/core/session_history.py +23 -0
- xdog_coding-2.4.4/src/xdog/coding/core/session_lifecycle.py +160 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/session_manager.py +93 -30
- xdog_coding-2.4.4/src/xdog/coding/core/session_preparation.py +20 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/session_staging.py +3 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/controller.py +111 -42
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/intake.py +1 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/ownership.py +8 -2
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/runtime.py +49 -59
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/store.py +51 -20
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/slash_commands.py +36 -12
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/main.py +22 -39
- xdog_coding-2.4.4/src/xdog/coding/modes/interactive/components/custom_editor.py +21 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/interactive_mode.py +29 -24
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/session_events.py +7 -6
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/goal_installed_consumer.py +7 -3
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_access_scope.py +5 -1
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_artifact_contract.py +4 -6
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_offline_inbox.py +2 -2
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_review_regressions.py +4 -6
- xdog_coding-2.4.4/tests/test_admission_navigation_owner.py +201 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_batch_mode_errors.py +6 -3
- xdog_coding-2.4.4/tests/test_cli_extension_trust.py +69 -0
- xdog_coding-2.4.4/tests/test_effective_configuration.py +88 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_goal_extension_views.py +8 -8
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_goal_lifecycle.py +3 -4
- xdog_coding-2.4.4/tests/test_history_commit_owner.py +114 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_controller.py +2 -2
- xdog_coding-2.4.4/tests/test_input_store_capacity.py +106 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_no_coding_rpc.py +2 -3
- xdog_coding-2.4.4/tests/test_owner_review_regressions.py +202 -0
- xdog_coding-2.4.4/tests/test_prompt_preparation.py +103 -0
- xdog_coding-2.4.4/tests/test_public_extension_commands.py +82 -0
- xdog_coding-2.4.4/tests/test_resource_loader.py +76 -0
- xdog_coding-2.4.4/tests/test_session_close_owner.py +345 -0
- xdog_coding-2.4.4/tests/test_session_identity_boundaries.py +153 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_ownership.py +7 -6
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_smoke.py +2 -2
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_slash_skills.py +3 -2
- xdog_coding-2.4.3/src/xdog/coding/core/extensions/__init__.py +0 -1
- xdog_coding-2.4.3/src/xdog/coding/core/extensions/loader.py +0 -116
- xdog_coding-2.4.3/src/xdog/coding/core/extensions/runner.py +0 -79
- xdog_coding-2.4.3/src/xdog/coding/core/extensions/types.py +0 -11
- xdog_coding-2.4.3/src/xdog/coding/modes/interactive/components/custom_editor.py +0 -30
- xdog_coding-2.4.3/tests/test_resource_loader.py +0 -50
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/.gitignore +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/LICENSE +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/LICENSE-EXCEPTION.md +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/bridge.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/cli.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/client.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/extensions.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress_backend.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress_main.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/args.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/config_selector.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/enqueue.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/file_processor.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/initial_message.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/list_models.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/cli/session_picker.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/bash_executor.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/canonical_source.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/child_agents.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/compaction.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/utils.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/context_messages.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/defaults.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/event_bus.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/exec_utils.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/inbox_commands.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/keybindings.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/messages.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/model_catalog.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/navigation.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/permissions.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/prompt_templates.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/remote_session.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/availability.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/batches.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_models.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_runtime.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_store.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_views.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/models.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/operations.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/router.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/turns.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/settings_manager.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/system_prompt.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/timings.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/tools/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/core/transcript_source.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/assistant_message.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/chat_log.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/editor_layout.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/footer.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/permission_prompt.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/tool_execution.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/user_message.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/provider_auth.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/run_status.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/session_presenter.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/theme.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/tool_renderers.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/modes/print_mode.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/py.typed +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/__init__.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/frontmatter.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/git.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/mime.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/shell.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/src/xdog/coding/utils/sleep.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/acp_owner_agent.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/batch_helpers.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/conftest.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/extension_session_helpers.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/fixtures/benchmark_tui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/fixtures/terminal_client.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/fixtures/terminal_review.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/session_owner_process.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_backend.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_batch_intake.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_bridge.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_cli.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_enqueue_cli.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_ingress.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_ingress_lifecycle.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_acp_optional_imports.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_active_tool_persistence.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_active_tool_retirement.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_after_run_compaction.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_after_run_name.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_agent_session.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_batch_config.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_batch_display.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_batch_turns.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_child_active_tools.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_child_agents.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_child_image_admission.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_child_image_submission.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_child_queue_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_cli_args.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_cli_config_selector.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_cli_file_processor.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_coding_config.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_command_artifact_export_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_compact_layout.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_compaction_controls_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_compaction_recovery.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_context_message_compaction.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_event_bus.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_command_results_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_core_readonly.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_editor_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_input_draft_isolation.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_input_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_navigation_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_provider_startup.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_readonly_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_extension_session_context_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_footer_context.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_goal_adapter.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_image_composer.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_image_lifecycle_admission.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_activation_navigation.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_auto_consume.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_commands.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_crash.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_display.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_store.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_inbox_v2.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_interactive_commands.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_interactive_keymap.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_interactive_mode.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_live_extensions.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_auth_projection.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_browser.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_catalog_watch_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_combined_watch_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_manual_picker_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_modern_browser_cancel.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_modern_browser_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_retired_gateway.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_roots_review_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_sampling_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_mcp_task_terminal.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_messages.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_native_session_queue.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_no_legacy_event_host.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_oauth_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_owned_native_model.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_permissions.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_prompt_templates.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_provider_oauth_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_queue_controls.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_readonly_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_removed_child_return_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_rendered_image_context.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_renderer_contracts_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_repository_review.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_retained_history.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_run_status.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_runtime_prompt.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_saved_child_drafts.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_saved_source_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_sdk_compaction_compat.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_sdk_runtime_compatibility.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_sdk_session_state.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_batches.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_control_fences.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_controller.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_history_display.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_input_store.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_manager.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_message_display.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_mode_routing.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_name_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_navigation.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_picker.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_router.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_staging.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_session_turns.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_settings_manager.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_skill_controls_ui.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_slash_commands.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_system_prompt.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_terminal_acceptance.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_timings.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_tools_browser.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_transcript_interaction.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_transcript_output.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_tui_usability.py +0 -0
- {xdog_coding-2.4.3 → xdog_coding-2.4.4}/tests/test_unified_inbox_review_fixes.py +0 -0
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: xdog-coding
|
|
3
|
+
Version: 2.4.4
|
|
4
|
+
Summary: Interactive coding agent CLI
|
|
5
|
+
Project-URL: Homepage, https://xdog.942295.xyz
|
|
6
|
+
Project-URL: Repository, https://github.com/litterzhang/xdog
|
|
7
|
+
Project-URL: Documentation, https://xdog.942295.xyz
|
|
8
|
+
Project-URL: Issues, https://github.com/litterzhang/xdog/issues
|
|
9
|
+
Author: HugeMan
|
|
10
|
+
License-Expression: AGPL-3.0-or-later
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: LICENSE-EXCEPTION.md
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: agent-client-protocol<0.13,>=0.12.1; python_version < '3.15'
|
|
23
|
+
Requires-Dist: click>=8.1.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Requires-Dist: xdog-agent>=2.4.4
|
|
27
|
+
Requires-Dist: xdog-ai[openai]>=2.4.4
|
|
28
|
+
Requires-Dist: xdog-tui>=2.4.4
|
|
29
|
+
Provides-Extra: skills
|
|
30
|
+
Requires-Dist: xdog-skills>=2.4.4; extra == 'skills'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
1
33
|
# xdog-coding
|
|
2
34
|
|
|
3
35
|
> Platform scope: **Linux only**. Non-Linux adapters and native-platform support
|
|
@@ -2623,3 +2655,68 @@ and widget layouts are removed. Native approval and recovery reviews remain host
|
|
|
2623
2655
|
owned; they expose no plugin layout or editor/session-mutation authority. Core TUI
|
|
2624
2656
|
overlays, transcript fullscreen, Unicode, clipping, cursor and tool-approval behavior
|
|
2625
2657
|
remain.
|
|
2658
|
+
|
|
2659
|
+
## Session ownership and reliable shutdown
|
|
2660
|
+
|
|
2661
|
+
Coding's TUI, print, SDK and ACP ingress share one session controller and Agent.
|
|
2662
|
+
Persistent writer locks live under `<sessions>/.owners`; they do not depend on
|
|
2663
|
+
`TMPDIR`. Short private Linux Unix socket/discovery files are separate, under
|
|
2664
|
+
`/tmp/xdog-coding-<uid>/<store-hash>`. Stop older Coding processes before upgrading:
|
|
2665
|
+
old binaries do not participate in this store-anchored writer-lock protocol. Do
|
|
2666
|
+
not run mixed old/new writers against the same session store.
|
|
2667
|
+
|
|
2668
|
+
SDK applications should `await session.aclose()` in `finally`. Closure is
|
|
2669
|
+
idempotent, waits for actual child/Goal/extension/MCP cleanup, and reports cleanup
|
|
2670
|
+
errors only after attempting the other resources. Cancellation of a waiter does
|
|
2671
|
+
not abandon the underlying close. `session.dispose()` requests the same close
|
|
2672
|
+
and returns a concurrent Future; synchronous applications can wait on `.result()`.
|
|
2673
|
+
Do not block an asynchronous caller loop with `.result()`; await `aclose()` instead.
|
|
2674
|
+
Synchronous construction and controls can be called with `asyncio.to_thread` when
|
|
2675
|
+
used from an async application. A receiver accepting a queued message does not
|
|
2676
|
+
require message approval; existing approval applies to tool execution only.
|
|
2677
|
+
|
|
2678
|
+
Automatic project instructions come **only** from the working directory's
|
|
2679
|
+
`AGENTS.md`, `.coding/INSTRUCTIONS.md` and `.coding/instructions.md`. There is no
|
|
2680
|
+
parent walk. Other harness configuration files are not automatic instruction
|
|
2681
|
+
sources; they remain ordinary files that users can explicitly read or attach under
|
|
2682
|
+
normal file-access and permission rules. There is no filename denylist.
|
|
2683
|
+
Each automatic source must be a regular UTF-8 file of at most 64 KiB; symlinks,
|
|
2684
|
+
special files and unreadable/oversized sources cause an explicit preparation error. Missing files are optional. These
|
|
2685
|
+
instructions are refreshed in owned off-loop preparation before a turn, reach the
|
|
2686
|
+
actual model prompt, and never grant tool permissions. The Agent alone renders
|
|
2687
|
+
skill indexes and session/turn-scoped bodies; loading a skill starts no observer,
|
|
2688
|
+
model, receiver or daemon.
|
|
2689
|
+
|
|
2690
|
+
`CreateSessionOptions.thinking_level` is honored, including explicit `"off"`.
|
|
2691
|
+
Initial `allowed_tools` configuration is a **tool selection**, not authorization:
|
|
2692
|
+
absent/null falls through to a lower layer, `[]` selects no tools, and a nonempty
|
|
2693
|
+
list selects those configured names. Caller options/overrides take precedence
|
|
2694
|
+
over saved explicit choices, then project and global configuration. Choices are
|
|
2695
|
+
not unioned. Unavailable saved names do not create tools or gain authority later;
|
|
2696
|
+
normal permission checks still apply to the selected tools.
|
|
2697
|
+
|
|
2698
|
+
The separate input history ledger has a common **64 MiB** read/write bound.
|
|
2699
|
+
Admission reserves final-state, batch-ID and bounded diagnostic space for every
|
|
2700
|
+
unfinished input; if it cannot fit, it is refused before acknowledgement. Errors
|
|
2701
|
+
retain up to 4096 characters with an explicit truncation marker; batch IDs are
|
|
2702
|
+
limited to 256 UTF-8 bytes. Accepted execution facts are never silently deleted.
|
|
2703
|
+
At capacity, explicitly start another session rather than automatically archiving
|
|
2704
|
+
or replaying requests. Recovery marks unfinished execution interrupted and never
|
|
2705
|
+
replays potentially executed tool effects automatically.
|
|
2706
|
+
|
|
2707
|
+
Ordinary turn history uses one immutable, original-owner disk commit, off the
|
|
2708
|
+
model loop, before publishing saved state and completing producer receipts.
|
|
2709
|
+
File replacement synchronizes the file and parent directory. A failed or
|
|
2710
|
+
uncertain history commit retains the live executed tail and fences further turns;
|
|
2711
|
+
close and explicitly reload/inspect the saved state before continuing. Concurrent
|
|
2712
|
+
metadata revision conflicts fail closed instead of overwriting newer facts.
|
|
2713
|
+
These are local filesystem/process guarantees, not hardware power-loss
|
|
2714
|
+
exactly-once execution or an OS security sandbox. No existing user data is migrated
|
|
2715
|
+
or discarded automatically.
|
|
2716
|
+
|
|
2717
|
+
Enabled extensions may declare a public slash name. The packaged `goal_ui`
|
|
2718
|
+
display exposes `/goals [GOAL_ID | page OFFSET]`; `/goal` remains the skill name.
|
|
2719
|
+
This is generic extension routing, not a Coding-specific Goal command. Public
|
|
2720
|
+
names appear in help/completion and cannot shadow builtin or skill commands;
|
|
2721
|
+
model tool names and permissions do not change. See
|
|
2722
|
+
`docs/extension-public-commands.md` for the shared Coding/Claw contract.
|
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: xdog-coding
|
|
3
|
-
Version: 2.4.3
|
|
4
|
-
Summary: Interactive coding agent CLI
|
|
5
|
-
Project-URL: Homepage, https://xdog.942295.xyz
|
|
6
|
-
Project-URL: Repository, https://github.com/litterzhang/xdog
|
|
7
|
-
Project-URL: Documentation, https://xdog.942295.xyz
|
|
8
|
-
Project-URL: Issues, https://github.com/litterzhang/xdog/issues
|
|
9
|
-
Author: HugeMan
|
|
10
|
-
License-Expression: AGPL-3.0-or-later
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
License-File: LICENSE-EXCEPTION.md
|
|
13
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
-
Classifier: Intended Audience :: Developers
|
|
15
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
-
Classifier: Typing :: Typed
|
|
21
|
-
Requires-Python: >=3.12
|
|
22
|
-
Requires-Dist: agent-client-protocol<0.13,>=0.12.1; python_version < '3.15'
|
|
23
|
-
Requires-Dist: click>=8.1.0
|
|
24
|
-
Requires-Dist: pydantic>=2.0
|
|
25
|
-
Requires-Dist: pyyaml>=6.0
|
|
26
|
-
Requires-Dist: xdog-agent>=2.4.3
|
|
27
|
-
Requires-Dist: xdog-ai[openai]>=2.4.3
|
|
28
|
-
Requires-Dist: xdog-tui>=2.4.3
|
|
29
|
-
Provides-Extra: skills
|
|
30
|
-
Requires-Dist: xdog-skills>=2.4.3; extra == 'skills'
|
|
31
|
-
Description-Content-Type: text/markdown
|
|
32
|
-
|
|
33
1
|
# xdog-coding
|
|
34
2
|
|
|
35
3
|
> Platform scope: **Linux only**. Non-Linux adapters and native-platform support
|
|
@@ -2655,3 +2623,68 @@ and widget layouts are removed. Native approval and recovery reviews remain host
|
|
|
2655
2623
|
owned; they expose no plugin layout or editor/session-mutation authority. Core TUI
|
|
2656
2624
|
overlays, transcript fullscreen, Unicode, clipping, cursor and tool-approval behavior
|
|
2657
2625
|
remain.
|
|
2626
|
+
|
|
2627
|
+
## Session ownership and reliable shutdown
|
|
2628
|
+
|
|
2629
|
+
Coding's TUI, print, SDK and ACP ingress share one session controller and Agent.
|
|
2630
|
+
Persistent writer locks live under `<sessions>/.owners`; they do not depend on
|
|
2631
|
+
`TMPDIR`. Short private Linux Unix socket/discovery files are separate, under
|
|
2632
|
+
`/tmp/xdog-coding-<uid>/<store-hash>`. Stop older Coding processes before upgrading:
|
|
2633
|
+
old binaries do not participate in this store-anchored writer-lock protocol. Do
|
|
2634
|
+
not run mixed old/new writers against the same session store.
|
|
2635
|
+
|
|
2636
|
+
SDK applications should `await session.aclose()` in `finally`. Closure is
|
|
2637
|
+
idempotent, waits for actual child/Goal/extension/MCP cleanup, and reports cleanup
|
|
2638
|
+
errors only after attempting the other resources. Cancellation of a waiter does
|
|
2639
|
+
not abandon the underlying close. `session.dispose()` requests the same close
|
|
2640
|
+
and returns a concurrent Future; synchronous applications can wait on `.result()`.
|
|
2641
|
+
Do not block an asynchronous caller loop with `.result()`; await `aclose()` instead.
|
|
2642
|
+
Synchronous construction and controls can be called with `asyncio.to_thread` when
|
|
2643
|
+
used from an async application. A receiver accepting a queued message does not
|
|
2644
|
+
require message approval; existing approval applies to tool execution only.
|
|
2645
|
+
|
|
2646
|
+
Automatic project instructions come **only** from the working directory's
|
|
2647
|
+
`AGENTS.md`, `.coding/INSTRUCTIONS.md` and `.coding/instructions.md`. There is no
|
|
2648
|
+
parent walk. Other harness configuration files are not automatic instruction
|
|
2649
|
+
sources; they remain ordinary files that users can explicitly read or attach under
|
|
2650
|
+
normal file-access and permission rules. There is no filename denylist.
|
|
2651
|
+
Each automatic source must be a regular UTF-8 file of at most 64 KiB; symlinks,
|
|
2652
|
+
special files and unreadable/oversized sources cause an explicit preparation error. Missing files are optional. These
|
|
2653
|
+
instructions are refreshed in owned off-loop preparation before a turn, reach the
|
|
2654
|
+
actual model prompt, and never grant tool permissions. The Agent alone renders
|
|
2655
|
+
skill indexes and session/turn-scoped bodies; loading a skill starts no observer,
|
|
2656
|
+
model, receiver or daemon.
|
|
2657
|
+
|
|
2658
|
+
`CreateSessionOptions.thinking_level` is honored, including explicit `"off"`.
|
|
2659
|
+
Initial `allowed_tools` configuration is a **tool selection**, not authorization:
|
|
2660
|
+
absent/null falls through to a lower layer, `[]` selects no tools, and a nonempty
|
|
2661
|
+
list selects those configured names. Caller options/overrides take precedence
|
|
2662
|
+
over saved explicit choices, then project and global configuration. Choices are
|
|
2663
|
+
not unioned. Unavailable saved names do not create tools or gain authority later;
|
|
2664
|
+
normal permission checks still apply to the selected tools.
|
|
2665
|
+
|
|
2666
|
+
The separate input history ledger has a common **64 MiB** read/write bound.
|
|
2667
|
+
Admission reserves final-state, batch-ID and bounded diagnostic space for every
|
|
2668
|
+
unfinished input; if it cannot fit, it is refused before acknowledgement. Errors
|
|
2669
|
+
retain up to 4096 characters with an explicit truncation marker; batch IDs are
|
|
2670
|
+
limited to 256 UTF-8 bytes. Accepted execution facts are never silently deleted.
|
|
2671
|
+
At capacity, explicitly start another session rather than automatically archiving
|
|
2672
|
+
or replaying requests. Recovery marks unfinished execution interrupted and never
|
|
2673
|
+
replays potentially executed tool effects automatically.
|
|
2674
|
+
|
|
2675
|
+
Ordinary turn history uses one immutable, original-owner disk commit, off the
|
|
2676
|
+
model loop, before publishing saved state and completing producer receipts.
|
|
2677
|
+
File replacement synchronizes the file and parent directory. A failed or
|
|
2678
|
+
uncertain history commit retains the live executed tail and fences further turns;
|
|
2679
|
+
close and explicitly reload/inspect the saved state before continuing. Concurrent
|
|
2680
|
+
metadata revision conflicts fail closed instead of overwriting newer facts.
|
|
2681
|
+
These are local filesystem/process guarantees, not hardware power-loss
|
|
2682
|
+
exactly-once execution or an OS security sandbox. No existing user data is migrated
|
|
2683
|
+
or discarded automatically.
|
|
2684
|
+
|
|
2685
|
+
Enabled extensions may declare a public slash name. The packaged `goal_ui`
|
|
2686
|
+
display exposes `/goals [GOAL_ID | page OFFSET]`; `/goal` remains the skill name.
|
|
2687
|
+
This is generic extension routing, not a Coding-specific Goal command. Public
|
|
2688
|
+
names appear in help/completion and cannot shadow builtin or skill commands;
|
|
2689
|
+
model tool names and permissions do not change. See
|
|
2690
|
+
`docs/extension-public-commands.md` for the shared Coding/Claw contract.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xdog-coding"
|
|
7
|
-
version = "2.4.
|
|
7
|
+
version = "2.4.4"
|
|
8
8
|
description = "Interactive coding agent CLI"
|
|
9
9
|
requires-python = ">=3.12"
|
|
10
10
|
classifiers = [
|
|
@@ -22,17 +22,17 @@ readme = "README.md"
|
|
|
22
22
|
license = "AGPL-3.0-or-later"
|
|
23
23
|
license-files = ["LICENSE", "LICENSE-EXCEPTION.md"]
|
|
24
24
|
dependencies = [
|
|
25
|
-
"xdog-ai[openai]>=2.4.
|
|
26
|
-
"xdog-agent>=2.4.
|
|
25
|
+
"xdog-ai[openai]>=2.4.4",
|
|
26
|
+
"xdog-agent>=2.4.4",
|
|
27
27
|
"agent-client-protocol>=0.12.1,<0.13; python_version < '3.15'",
|
|
28
|
-
"xdog-tui>=2.4.
|
|
28
|
+
"xdog-tui>=2.4.4",
|
|
29
29
|
"pyyaml>=6.0",
|
|
30
30
|
"click>=8.1.0",
|
|
31
31
|
"pydantic>=2.0",
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
[project.optional-dependencies]
|
|
35
|
-
skills = ["xdog-skills>=2.4.
|
|
35
|
+
skills = ["xdog-skills>=2.4.4"]
|
|
36
36
|
|
|
37
37
|
[project.urls]
|
|
38
38
|
Homepage = "https://xdog.942295.xyz"
|
|
@@ -89,17 +89,19 @@ class CodingBackend:
|
|
|
89
89
|
try:
|
|
90
90
|
session = await asyncio.shield(task)
|
|
91
91
|
except asyncio.CancelledError:
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
from xdog.agent.async_work import wait_owned
|
|
93
|
+
async def settle_construction() -> None:
|
|
94
|
+
late_session = await task
|
|
95
|
+
await late_session.aclose()
|
|
96
|
+
await wait_owned(asyncio.create_task(settle_construction(), name='coding-acp-canceled-construction'))
|
|
94
97
|
raise
|
|
95
|
-
runtime = SessionRuntime(session, bound=False, router=self.router)
|
|
96
|
-
runtime.start()
|
|
97
98
|
try:
|
|
99
|
+
runtime = SessionRuntime(session, bound=False, router=self.router)
|
|
100
|
+
runtime.start()
|
|
98
101
|
from xdog.coding.acp.server import serve_local
|
|
99
|
-
|
|
100
102
|
server = await serve_local(runtime)
|
|
101
103
|
except BaseException:
|
|
102
|
-
await
|
|
104
|
+
await session.aclose()
|
|
103
105
|
raise
|
|
104
106
|
self._owned[session.session_id] = peer.id, runtime, server
|
|
105
107
|
ref = SessionRef(session.session_id, session.working_dir, runtime.controller.generation)
|
|
@@ -300,31 +302,51 @@ class CodingBackend:
|
|
|
300
302
|
await asyncio.wrap_future(running.controller.cancel(running.ticket.id, peer_id=peer.id))
|
|
301
303
|
|
|
302
304
|
async def disconnect(self, peer: Peer) -> None:
|
|
303
|
-
|
|
305
|
+
from functools import partial
|
|
306
|
+
|
|
307
|
+
from xdog.agent.async_work import settle_cleanup
|
|
304
308
|
pending = tuple(row for key, row in self._running.items() if key[0] == peer.id)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
309
|
+
async def ingress() -> None:
|
|
310
|
+
await self._inbox.disconnect(peer)
|
|
311
|
+
async def requests() -> None:
|
|
312
|
+
for row in pending:
|
|
313
|
+
if row.ticket is None and not row.task.cancelling():
|
|
314
|
+
row.task.cancel()
|
|
315
|
+
async def disconnect(controller: SessionController) -> None:
|
|
316
|
+
await asyncio.wrap_future(controller.disconnect(peer.id))
|
|
317
|
+
async def join() -> None:
|
|
318
|
+
tasks = [row.task for row in pending if row.task is not asyncio.current_task()]
|
|
319
|
+
for task in tasks:
|
|
320
|
+
if not task.done() and not task.cancelling():
|
|
321
|
+
task.cancel()
|
|
322
|
+
if tasks:
|
|
323
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
324
|
+
controllers = {row.controller for row in pending}
|
|
325
|
+
await settle_cleanup(*(partial(disconnect, controller) for controller in controllers),
|
|
326
|
+
join, message='ACP request retirement failed')
|
|
327
|
+
async def remote(key: tuple[str, str], attachment: AcpAttachment) -> None:
|
|
328
|
+
try:
|
|
329
|
+
await attachment.close()
|
|
330
|
+
finally:
|
|
331
|
+
self._remote.pop(key, None)
|
|
332
|
+
async def owned(identifier: str, runtime: SessionRuntime) -> None:
|
|
333
|
+
try:
|
|
334
|
+
# The session owns its CURRENT endpoint too. Closing the saved
|
|
335
|
+
# old endpoint first would bypass all remaining resource cleanup.
|
|
336
|
+
await runtime.session.aclose()
|
|
337
|
+
finally:
|
|
338
|
+
if runtime.session._lease is None:
|
|
339
|
+
self._owned.pop(identifier, None)
|
|
340
|
+
async def references() -> None:
|
|
341
|
+
for key in tuple(self._refs):
|
|
342
|
+
if key[0] == peer.id:
|
|
343
|
+
self._refs.pop(key, None)
|
|
344
|
+
owned_sessions = tuple(self._owned.items())
|
|
345
|
+
await settle_cleanup(ingress, requests,
|
|
346
|
+
*(partial(remote, key, attachment) for key, attachment in tuple(self._remote.items()) if key[0] == peer.id),
|
|
347
|
+
*(partial(owned, identifier, runtime) for identifier, (owner, runtime, _server) in owned_sessions
|
|
348
|
+
if owner == peer.id), references, message='ACP peer cleanup failed')
|
|
349
|
+
|
|
328
350
|
async def extension(self, peer: Peer, method: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
329
351
|
if method in {'xdog/enqueue', 'xdog/inbox_status'}:
|
|
330
352
|
target = params.get('session_id')
|
|
@@ -22,6 +22,7 @@ class LocalServer:
|
|
|
22
22
|
self.identity: tuple[int, int] | None = None
|
|
23
23
|
self.server: asyncio.AbstractServer | None = None
|
|
24
24
|
self.closing = False
|
|
25
|
+
self._closing: asyncio.Task[None] | None = None
|
|
25
26
|
self.writers: set[asyncio.StreamWriter] = set()
|
|
26
27
|
self.tasks: set[asyncio.Task[None]] = set()
|
|
27
28
|
|
|
@@ -47,24 +48,38 @@ class LocalServer:
|
|
|
47
48
|
await writer.wait_closed()
|
|
48
49
|
|
|
49
50
|
async def close(self) -> None:
|
|
50
|
-
|
|
51
|
-
if self.
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
51
|
+
from xdog.agent.async_work import wait_owned
|
|
52
|
+
if self._closing is None:
|
|
53
|
+
self.closing = True
|
|
54
|
+
self._closing = asyncio.create_task(self._close(), name='coding-endpoint-close')
|
|
55
|
+
await wait_owned(self._closing)
|
|
56
|
+
|
|
57
|
+
async def _close(self) -> None:
|
|
58
|
+
from xdog.agent.async_work import settle_cleanup
|
|
59
|
+
from xdog.coding.core.session_lifecycle import settle_sync
|
|
60
|
+
async def transports() -> None:
|
|
61
|
+
steps = [writer.close for writer in tuple(self.writers)]
|
|
62
|
+
if self.server is not None:
|
|
63
|
+
steps.insert(0, self.server.close)
|
|
64
|
+
settle_sync(*steps, message='ACP transport close failed')
|
|
65
|
+
async def server() -> None:
|
|
66
|
+
if self.server is not None:
|
|
67
|
+
await self.server.wait_closed()
|
|
68
|
+
self.server = None
|
|
69
|
+
async def peers() -> None:
|
|
70
|
+
if self.tasks:
|
|
71
|
+
# Disconnect/request errors are peer outcomes, not cleanup errors.
|
|
72
|
+
await asyncio.gather(*tuple(self.tasks), return_exceptions=True)
|
|
73
|
+
async def unlink() -> None:
|
|
74
|
+
path = self.record.address
|
|
75
|
+
if path.exists():
|
|
76
|
+
info = path.lstat()
|
|
77
|
+
if (stat.S_ISSOCK(info.st_mode) and info.st_uid == os.getuid()
|
|
78
|
+
and (info.st_dev, info.st_ino) == self.identity):
|
|
79
|
+
path.unlink()
|
|
80
|
+
async def registry() -> None:
|
|
81
|
+
self.runtime.registry.remove(self.record)
|
|
82
|
+
await settle_cleanup(transports, server, peers, unlink, registry, message='ACP endpoint cleanup failed')
|
|
68
83
|
|
|
69
84
|
|
|
70
85
|
async def serve_local(runtime: SessionRuntime) -> LocalServer:
|
|
@@ -21,6 +21,20 @@ from typing import Any
|
|
|
21
21
|
from pydantic import BaseModel, Field, field_validator
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
class InvalidToolSelection(ValueError):
|
|
25
|
+
"""Explicit invalid tool selection must not silently become all tools."""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def validate_tool_selection(value: object) -> tuple[str, ...] | None:
|
|
29
|
+
if value is None:
|
|
30
|
+
return None
|
|
31
|
+
from xdog.agent.extensions.active_tools import names
|
|
32
|
+
try:
|
|
33
|
+
return names(value)
|
|
34
|
+
except (TypeError, ValueError) as exc:
|
|
35
|
+
raise InvalidToolSelection('allowed_tools must be a list of distinct tool names or null') from exc
|
|
36
|
+
|
|
37
|
+
|
|
24
38
|
class InvalidBatchLimit(ValueError):
|
|
25
39
|
"""An explicit malformed owner setting must not fall back silently."""
|
|
26
40
|
|
|
@@ -37,7 +51,7 @@ def validate_max_messages_per_turn(value: object) -> int:
|
|
|
37
51
|
|
|
38
52
|
MONOREPO_NAME = "xdog"
|
|
39
53
|
APP_NAME = "coding"
|
|
40
|
-
VERSION = "2.4.
|
|
54
|
+
VERSION = "2.4.4"
|
|
41
55
|
PROJECT_DIR_NAME = ".coding"
|
|
42
56
|
ENV_OVERRIDE = "CODING_DIR"
|
|
43
57
|
|
|
@@ -202,7 +216,7 @@ class GlobalConfig(BaseModel):
|
|
|
202
216
|
child_presets: Any = Field(default_factory=dict)
|
|
203
217
|
mcp_servers: dict[str, Any] = Field(default_factory=dict)
|
|
204
218
|
mcp_credential_backend: Any = 'file' # Validated at the host boundary; never defaults on an invalid native choice.
|
|
205
|
-
allowed_tools: list[str] =
|
|
219
|
+
allowed_tools: list[str] | None = None
|
|
206
220
|
custom_instructions: str = ""
|
|
207
221
|
|
|
208
222
|
@classmethod
|
|
@@ -215,8 +229,10 @@ class GlobalConfig(BaseModel):
|
|
|
215
229
|
raw = json.loads(target.read_text(encoding="utf-8"))
|
|
216
230
|
if isinstance(raw, dict) and 'max_messages_per_turn' in raw:
|
|
217
231
|
validate_max_messages_per_turn(raw['max_messages_per_turn'])
|
|
232
|
+
if isinstance(raw, dict) and 'allowed_tools' in raw:
|
|
233
|
+
validate_tool_selection(raw['allowed_tools'])
|
|
218
234
|
return cls.model_validate(raw)
|
|
219
|
-
except InvalidBatchLimit:
|
|
235
|
+
except (InvalidBatchLimit, InvalidToolSelection):
|
|
220
236
|
raise
|
|
221
237
|
except Exception:
|
|
222
238
|
return cls()
|
|
@@ -248,7 +264,7 @@ class ProjectConfig(BaseModel):
|
|
|
248
264
|
model: str | None = None
|
|
249
265
|
thinking_level: str | None = None
|
|
250
266
|
permission_mode: str | None = None
|
|
251
|
-
allowed_tools: list[str] =
|
|
267
|
+
allowed_tools: list[str] | None = None
|
|
252
268
|
custom_instructions: str = ""
|
|
253
269
|
extensions: list[str] = Field(default_factory=list)
|
|
254
270
|
mcp_servers: dict[str, Any] = Field(default_factory=dict)
|
|
@@ -262,8 +278,10 @@ class ProjectConfig(BaseModel):
|
|
|
262
278
|
raw = json.loads(target.read_text(encoding="utf-8"))
|
|
263
279
|
if isinstance(raw, dict) and 'max_messages_per_turn' in raw:
|
|
264
280
|
validate_max_messages_per_turn(raw['max_messages_per_turn'])
|
|
281
|
+
if isinstance(raw, dict) and 'allowed_tools' in raw:
|
|
282
|
+
validate_tool_selection(raw['allowed_tools'])
|
|
265
283
|
return cls.model_validate(raw)
|
|
266
|
-
except InvalidBatchLimit:
|
|
284
|
+
except (InvalidBatchLimit, InvalidToolSelection):
|
|
267
285
|
raise
|
|
268
286
|
except Exception:
|
|
269
287
|
return cls()
|
|
@@ -280,7 +298,7 @@ class RuntimeConfig:
|
|
|
280
298
|
model: str
|
|
281
299
|
thinking_level: str
|
|
282
300
|
permission_mode: str
|
|
283
|
-
allowed_tools: tuple[str, ...]
|
|
301
|
+
allowed_tools: tuple[str, ...] | None
|
|
284
302
|
custom_instructions: str
|
|
285
303
|
extensions: tuple[str, ...]
|
|
286
304
|
working_dir: str
|
|
@@ -295,19 +313,23 @@ class RuntimeConfig:
|
|
|
295
313
|
project_cfg: ProjectConfig | None = None,
|
|
296
314
|
working_dir: Path | None = None,
|
|
297
315
|
overrides: dict[str, Any] | None = None,
|
|
316
|
+
session_settings: dict[str, Any] | None = None,
|
|
298
317
|
) -> RuntimeConfig:
|
|
299
318
|
"""Merge global, project and CLI overrides into a single config."""
|
|
300
319
|
ov = overrides or {}
|
|
301
320
|
pcfg = project_cfg or ProjectConfig()
|
|
302
|
-
|
|
303
|
-
|
|
321
|
+
saved = session_settings or {}
|
|
322
|
+
model = ov.get('model') or saved.get('model') or pcfg.model or global_cfg.default_model
|
|
323
|
+
thinking = (ov.get('thinking_level') or saved.get('thinking_level')
|
|
324
|
+
or pcfg.thinking_level or global_cfg.thinking_level)
|
|
304
325
|
permission_mode = (
|
|
305
326
|
ov.get("permission_mode")
|
|
306
327
|
or pcfg.permission_mode
|
|
307
328
|
or global_cfg.permission_mode
|
|
308
329
|
)
|
|
309
330
|
|
|
310
|
-
|
|
331
|
+
selection = next((value for value in (ov.get('allowed_tools'), saved.get('allowed_tools'),
|
|
332
|
+
pcfg.allowed_tools, global_cfg.allowed_tools) if value is not None), None)
|
|
311
333
|
merged_ext = list(global_cfg.extensions) + list(pcfg.extensions)
|
|
312
334
|
|
|
313
335
|
instructions_parts: list[str] = []
|
|
@@ -320,13 +342,14 @@ class RuntimeConfig:
|
|
|
320
342
|
model=model,
|
|
321
343
|
thinking_level=thinking,
|
|
322
344
|
permission_mode=permission_mode,
|
|
323
|
-
allowed_tools=
|
|
345
|
+
allowed_tools=validate_tool_selection(selection),
|
|
324
346
|
custom_instructions="\n\n".join(instructions_parts),
|
|
325
347
|
extensions=tuple(merged_ext),
|
|
326
348
|
working_dir=str(working_dir or Path.cwd()),
|
|
327
349
|
platform_info=PlatformInfo.detect(),
|
|
328
350
|
max_messages_per_turn=validate_max_messages_per_turn(
|
|
329
351
|
ov['max_messages_per_turn'] if 'max_messages_per_turn' in ov else
|
|
352
|
+
saved['max_messages_per_turn'] if 'max_messages_per_turn' in saved else
|
|
330
353
|
pcfg.max_messages_per_turn if pcfg.max_messages_per_turn is not None else
|
|
331
354
|
global_cfg.max_messages_per_turn),
|
|
332
355
|
)
|