xdog-coding 2.4.2__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.
Files changed (255) hide show
  1. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/PKG-INFO +119 -21
  2. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/README.md +113 -17
  3. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/pyproject.toml +7 -4
  4. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/__init__.py +1 -1
  5. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/backend.py +52 -30
  6. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/server.py +33 -18
  7. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/config.py +33 -10
  8. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/agent_session.py +319 -158
  9. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/child_agents.py +35 -9
  10. xdog_coding-2.4.4/src/xdog/coding/core/command_names.py +19 -0
  11. xdog_coding-2.4.4/src/xdog/coding/core/goal_adapter.py +370 -0
  12. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/resource_loader.py +46 -26
  13. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sdk.py +35 -57
  14. xdog_coding-2.4.4/src/xdog/coding/core/session_history.py +23 -0
  15. xdog_coding-2.4.4/src/xdog/coding/core/session_lifecycle.py +160 -0
  16. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/session_manager.py +93 -30
  17. xdog_coding-2.4.4/src/xdog/coding/core/session_preparation.py +20 -0
  18. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/session_staging.py +3 -0
  19. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/controller.py +143 -50
  20. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_models.py +1 -1
  21. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_runtime.py +56 -14
  22. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_store.py +37 -4
  23. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/intake.py +1 -0
  24. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/ownership.py +8 -2
  25. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/runtime.py +50 -59
  26. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/store.py +51 -20
  27. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/slash_commands.py +45 -12
  28. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/main.py +22 -39
  29. xdog_coding-2.4.4/src/xdog/coding/modes/interactive/components/custom_editor.py +21 -0
  30. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/interactive_mode.py +30 -27
  31. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/session_events.py +10 -12
  32. xdog_coding-2.4.4/tests/goal_installed_consumer.py +237 -0
  33. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_access_scope.py +11 -6
  34. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_artifact_contract.py +7 -5
  35. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_offline_inbox.py +2 -2
  36. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_review_regressions.py +48 -19
  37. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_active_tool_retirement.py +13 -8
  38. xdog_coding-2.4.4/tests/test_admission_navigation_owner.py +201 -0
  39. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_batch_mode_errors.py +6 -3
  40. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_child_agents.py +50 -9
  41. xdog_coding-2.4.4/tests/test_cli_extension_trust.py +69 -0
  42. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_compaction_controls_ui.py +3 -2
  43. xdog_coding-2.4.4/tests/test_effective_configuration.py +88 -0
  44. xdog_coding-2.4.4/tests/test_goal_adapter.py +302 -0
  45. xdog_coding-2.4.4/tests/test_goal_extension_views.py +212 -0
  46. xdog_coding-2.4.4/tests/test_goal_lifecycle.py +267 -0
  47. xdog_coding-2.4.4/tests/test_history_commit_owner.py +114 -0
  48. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_auto_consume.py +5 -2
  49. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_controller.py +2 -2
  50. xdog_coding-2.4.4/tests/test_input_store_capacity.py +106 -0
  51. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_no_coding_rpc.py +2 -3
  52. xdog_coding-2.4.4/tests/test_owner_review_regressions.py +202 -0
  53. xdog_coding-2.4.4/tests/test_prompt_preparation.py +103 -0
  54. xdog_coding-2.4.4/tests/test_public_extension_commands.py +82 -0
  55. xdog_coding-2.4.4/tests/test_resource_loader.py +76 -0
  56. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_runtime_prompt.py +3 -2
  57. xdog_coding-2.4.4/tests/test_session_close_owner.py +345 -0
  58. xdog_coding-2.4.4/tests/test_session_identity_boundaries.py +153 -0
  59. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_mode_routing.py +2 -0
  60. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_ownership.py +7 -6
  61. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_smoke.py +2 -2
  62. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_slash_skills.py +5 -2
  63. xdog_coding-2.4.4/tests/test_unified_inbox_review_fixes.py +397 -0
  64. xdog_coding-2.4.2/src/xdog/coding/core/extensions/__init__.py +0 -1
  65. xdog_coding-2.4.2/src/xdog/coding/core/extensions/loader.py +0 -116
  66. xdog_coding-2.4.2/src/xdog/coding/core/extensions/runner.py +0 -79
  67. xdog_coding-2.4.2/src/xdog/coding/core/extensions/types.py +0 -11
  68. xdog_coding-2.4.2/src/xdog/coding/modes/interactive/components/custom_editor.py +0 -30
  69. xdog_coding-2.4.2/tests/test_resource_loader.py +0 -50
  70. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/.gitignore +0 -0
  71. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/LICENSE +0 -0
  72. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/LICENSE-EXCEPTION.md +0 -0
  73. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/__init__.py +0 -0
  74. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/bridge.py +0 -0
  75. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/cli.py +0 -0
  76. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/client.py +0 -0
  77. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/extensions.py +0 -0
  78. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress.py +0 -0
  79. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress_backend.py +0 -0
  80. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/acp/ingress_main.py +0 -0
  81. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/__init__.py +0 -0
  82. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/args.py +0 -0
  83. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/config_selector.py +0 -0
  84. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/enqueue.py +0 -0
  85. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/file_processor.py +0 -0
  86. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/initial_message.py +0 -0
  87. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/list_models.py +0 -0
  88. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/cli/session_picker.py +0 -0
  89. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/__init__.py +0 -0
  90. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/bash_executor.py +0 -0
  91. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/canonical_source.py +0 -0
  92. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/__init__.py +0 -0
  93. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/compaction.py +0 -0
  94. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/compaction/utils.py +0 -0
  95. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/context_messages.py +0 -0
  96. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/defaults.py +0 -0
  97. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/event_bus.py +0 -0
  98. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/exec_utils.py +0 -0
  99. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/inbox_commands.py +0 -0
  100. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/keybindings.py +0 -0
  101. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/messages.py +0 -0
  102. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/model_catalog.py +0 -0
  103. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/navigation.py +0 -0
  104. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/permissions.py +0 -0
  105. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/prompt_templates.py +0 -0
  106. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/remote_session.py +0 -0
  107. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/__init__.py +0 -0
  108. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/availability.py +0 -0
  109. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/batches.py +0 -0
  110. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/inbox_views.py +0 -0
  111. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/models.py +0 -0
  112. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/operations.py +0 -0
  113. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/router.py +0 -0
  114. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/sessions/turns.py +0 -0
  115. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/settings_manager.py +0 -0
  116. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/system_prompt.py +0 -0
  117. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/timings.py +0 -0
  118. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/tools/__init__.py +0 -0
  119. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/core/transcript_source.py +0 -0
  120. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/__init__.py +0 -0
  121. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/__init__.py +0 -0
  122. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/__init__.py +0 -0
  123. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/assistant_message.py +0 -0
  124. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/chat_log.py +0 -0
  125. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/editor_layout.py +0 -0
  126. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/footer.py +0 -0
  127. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/permission_prompt.py +0 -0
  128. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/tool_execution.py +0 -0
  129. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/components/user_message.py +0 -0
  130. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/provider_auth.py +0 -0
  131. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/run_status.py +0 -0
  132. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/session_presenter.py +0 -0
  133. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/theme.py +0 -0
  134. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/interactive/tool_renderers.py +0 -0
  135. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/modes/print_mode.py +0 -0
  136. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/py.typed +0 -0
  137. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/__init__.py +0 -0
  138. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/frontmatter.py +0 -0
  139. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/git.py +0 -0
  140. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/mime.py +0 -0
  141. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/shell.py +0 -0
  142. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/src/xdog/coding/utils/sleep.py +0 -0
  143. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/acp_owner_agent.py +0 -0
  144. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/batch_helpers.py +0 -0
  145. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/conftest.py +0 -0
  146. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/extension_session_helpers.py +0 -0
  147. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/fixtures/benchmark_tui.py +0 -0
  148. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/fixtures/terminal_client.py +0 -0
  149. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/fixtures/terminal_review.py +0 -0
  150. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/session_owner_process.py +0 -0
  151. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_backend.py +0 -0
  152. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_batch_intake.py +0 -0
  153. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_bridge.py +0 -0
  154. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_cli.py +0 -0
  155. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_enqueue_cli.py +0 -0
  156. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_ingress.py +0 -0
  157. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_ingress_lifecycle.py +0 -0
  158. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_acp_optional_imports.py +0 -0
  159. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_active_tool_persistence.py +0 -0
  160. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_after_run_compaction.py +0 -0
  161. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_after_run_name.py +0 -0
  162. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_agent_session.py +0 -0
  163. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_batch_config.py +0 -0
  164. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_batch_display.py +0 -0
  165. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_batch_turns.py +0 -0
  166. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_child_active_tools.py +0 -0
  167. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_child_image_admission.py +0 -0
  168. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_child_image_submission.py +0 -0
  169. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_child_queue_ui.py +0 -0
  170. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_cli_args.py +0 -0
  171. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_cli_config_selector.py +0 -0
  172. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_cli_file_processor.py +0 -0
  173. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_coding_config.py +0 -0
  174. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_command_artifact_export_ui.py +0 -0
  175. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_compact_layout.py +0 -0
  176. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_compaction_recovery.py +0 -0
  177. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_context_message_compaction.py +0 -0
  178. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_event_bus.py +0 -0
  179. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_command_results_ui.py +0 -0
  180. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_core_readonly.py +0 -0
  181. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_editor_ui.py +0 -0
  182. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_input_draft_isolation.py +0 -0
  183. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_input_ui.py +0 -0
  184. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_navigation_ui.py +0 -0
  185. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_provider_startup.py +0 -0
  186. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_readonly_ui.py +0 -0
  187. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_extension_session_context_ui.py +0 -0
  188. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_footer_context.py +0 -0
  189. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_image_composer.py +0 -0
  190. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_image_lifecycle_admission.py +0 -0
  191. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_activation_navigation.py +0 -0
  192. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_commands.py +0 -0
  193. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_crash.py +0 -0
  194. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_display.py +0 -0
  195. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_store.py +0 -0
  196. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_inbox_v2.py +0 -0
  197. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_interactive_commands.py +0 -0
  198. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_interactive_keymap.py +0 -0
  199. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_interactive_mode.py +0 -0
  200. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_live_extensions.py +0 -0
  201. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_auth_projection.py +0 -0
  202. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_browser.py +0 -0
  203. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_catalog_watch_ui.py +0 -0
  204. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_combined_watch_ui.py +0 -0
  205. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_manual_picker_ui.py +0 -0
  206. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_modern_browser_cancel.py +0 -0
  207. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_modern_browser_ui.py +0 -0
  208. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_retired_gateway.py +0 -0
  209. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_roots_review_ui.py +0 -0
  210. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_sampling_ui.py +0 -0
  211. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_mcp_task_terminal.py +0 -0
  212. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_messages.py +0 -0
  213. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_native_session_queue.py +0 -0
  214. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_no_legacy_event_host.py +0 -0
  215. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_oauth_ui.py +0 -0
  216. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_owned_native_model.py +0 -0
  217. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_permissions.py +0 -0
  218. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_prompt_templates.py +0 -0
  219. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_provider_oauth_ui.py +0 -0
  220. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_queue_controls.py +0 -0
  221. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_readonly_ui.py +0 -0
  222. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_removed_child_return_ui.py +0 -0
  223. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_rendered_image_context.py +0 -0
  224. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_renderer_contracts_ui.py +0 -0
  225. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_repository_review.py +0 -0
  226. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_retained_history.py +0 -0
  227. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_run_status.py +0 -0
  228. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_saved_child_drafts.py +0 -0
  229. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_saved_source_ui.py +0 -0
  230. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_sdk_compaction_compat.py +0 -0
  231. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_sdk_runtime_compatibility.py +0 -0
  232. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_sdk_session_state.py +0 -0
  233. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_batches.py +0 -0
  234. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_control_fences.py +0 -0
  235. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_controller.py +0 -0
  236. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_history_display.py +0 -0
  237. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_input_store.py +0 -0
  238. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_manager.py +0 -0
  239. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_message_display.py +0 -0
  240. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_name_ui.py +0 -0
  241. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_navigation.py +0 -0
  242. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_picker.py +0 -0
  243. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_router.py +0 -0
  244. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_staging.py +0 -0
  245. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_session_turns.py +0 -0
  246. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_settings_manager.py +0 -0
  247. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_skill_controls_ui.py +0 -0
  248. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_slash_commands.py +0 -0
  249. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_system_prompt.py +0 -0
  250. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_terminal_acceptance.py +0 -0
  251. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_timings.py +0 -0
  252. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_tools_browser.py +0 -0
  253. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_transcript_interaction.py +0 -0
  254. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_transcript_output.py +0 -0
  255. {xdog_coding-2.4.2 → xdog_coding-2.4.4}/tests/test_tui_usability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: xdog-coding
3
- Version: 2.4.2
3
+ Version: 2.4.4
4
4
  Summary: Interactive coding agent CLI
5
5
  Project-URL: Homepage, https://xdog.942295.xyz
6
6
  Project-URL: Repository, https://github.com/litterzhang/xdog
@@ -23,9 +23,11 @@ Requires-Dist: agent-client-protocol<0.13,>=0.12.1; python_version < '3.15'
23
23
  Requires-Dist: click>=8.1.0
24
24
  Requires-Dist: pydantic>=2.0
25
25
  Requires-Dist: pyyaml>=6.0
26
- Requires-Dist: xdog-agent>=2.4.2
27
- Requires-Dist: xdog-ai[openai]>=2.4.2
28
- Requires-Dist: xdog-tui>=2.4.2
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'
29
31
  Description-Content-Type: text/markdown
30
32
 
31
33
  # xdog-coding
@@ -578,7 +580,8 @@ continuation silently reconnects, replays POSTs or expands configured disclosure
578
580
 
579
581
  ### Task planning and host read-only scope
580
582
 
581
- The builtin **`xdog-planning`** skill uses ordinary conversation or task documents
583
+ The builtin **`xdog-planning`** skill, supplied by `xdog-skills` (install the
584
+ `skills` extra), uses ordinary conversation or task documents
582
585
  for objectives, dependencies, acceptance criteria and evidence-backed progress.
583
586
  It does not create a separate plan database, inspector, execution mode or model
584
587
  loop. The former `/plan`, `PlanPanel` and `update_plan` UI/tool APIs are removed.
@@ -775,7 +778,7 @@ none of these interfaces grants tool permission or full Pi API compatibility.
775
778
 
776
779
  ### Supervised child agents
777
780
 
778
- `/agents start TASK` starts bounded read-only child work. `/agents start --inherit
781
+ `/agents start TASK` starts host-managed read-only child work. `/agents start --inherit
779
782
  TASK` inherits the current host policy; it does not copy approval grants or bypass
780
783
  read-only. Inspect with `/agents list` or `/agents inspect ID`; use `steer ID TEXT`,
781
784
  `follow-up ID TEXT`, `cancel ID`, `wait ID` and `close ID` under `/agents`.
@@ -784,10 +787,34 @@ recursively delegate through their parent's supervision tools.
784
787
 
785
788
  Children share the workspace, so coordinate conflicting writes. Context is copied
786
789
  at admission through a complete tool/result checkpoint. Model/options/tool execution
787
- mode are inherited. Defaults are three active children, 16 retained records,
788
- 120-second execution deadline, 16 model calls and a 32,000 reported-token stop
789
- threshold—not exact billing. Output limits are clamped; input accounting can
790
- overshoot on the final request. Cleanup/persistence may outlast the execution deadline.
790
+ mode are inherited. There is no fixed concurrent-child or retained-record count
791
+ limit, elapsed-time deadline, model-call cap or cumulative reported-token stop
792
+ threshold. The main Agent/host manages lifecycle with cancel/wait/close. Usage
793
+ counters remain reported usage, not exact billable accounting; actual model
794
+ output/context limits, permissions and message/input/image/per-file capacities
795
+ still apply. Complete history uses atomic segmented persistence instead of a
796
+ cumulative 512 KiB / 2,000-message execution cutoff; tool/result pairs are not
797
+ silently truncated.
798
+
799
+ Coding and Claw child factories explicitly enable the Agent's existing built-in
800
+ compaction policy through `AgentConfig(compaction=selected.compaction(child_stream))`
801
+ and provide `archive_compaction=store.archive_compaction` to the supervisor.
802
+ This does **not** change the generic Agent default: automatic compaction is off
803
+ unless explicitly configured. The selected helper uses the executing adapter's
804
+ real context/prompt/output capacity; unknown metadata, context capacity or output
805
+ reserve returns `None` (auto-compaction remains off), not a guessed fallback.
806
+ A host requiring automatic compaction must reject that case or explicitly supply
807
+ trusted capacity/reserve through native `CompactionConfig`.
808
+
809
+ With the policy enabled, one long tool turn can compact repeatedly at safe paired
810
+ boundaries. The supervisor waits for a durable full pre-compaction snapshot before
811
+ the native summary request starts. Archive, summary or stream-cleanup failure does
812
+ not commit a history cut, and cancellation settles owned writes/cleanup. The native
813
+ summary's per-request timeout/capacity checks remain; there is no replacement child
814
+ lifetime cap. Inspect shows the current retained context, possibly with summaries;
815
+ `children.store.compaction_archives(child_id)` reads full earlier snapshots without
816
+ replay. These child archives are separate from the parent session's `/tree`
817
+ compaction checkpoints.
791
818
 
792
819
  Each child has independent Coding approvals and extension workers/state. Parent
793
820
  validation/context hooks and current read-only/permission gates remain authoritative;
@@ -830,10 +857,10 @@ still uses silent no-UI answers to avoid borrowing its separate dialog reservati
830
857
  Complex extension forms are removed; basic child dialogs retain these ownership and cancellation checks.
831
858
 
832
859
 
833
- ### Child specialization and limits
860
+ ### Child specialization and protocol limits
834
861
 
835
862
  `/agents start --label Reviewer --instructions "Inspect only" --tools filesystem,current_time
836
- --fresh --timeout 60 --calls 4 --tokens 8000 -- TASK` specializes a child without
863
+ --fresh -- TASK` specializes a child without
837
864
  changing parent permissions. Options precede the task; `--` preserves a task that
838
865
  starts with flags. Plain tasks preserve quotes/newlines. `--tools none` gives the
839
866
  child no executable tools; otherwise selected names must exist in its inherited tool
@@ -842,11 +869,15 @@ fail visibly. Instructions append to, rather than replace, parent restrictions.
842
869
 
843
870
  In `/agents` press `n`, then Ctrl+G for settings JSON. Supported keys are `label`,
844
871
  `instructions`, `tools` (array or null for inherited tools), `inherit_context`,
845
- `timeout`, `max_model_calls` and `max_tokens`. Enter applies the settings draft only;
872
+ `model`, `thinking` and `preset`. Enter applies the settings draft only;
846
873
  start review requires every page to be painted before confirmation. Resize invalidates
847
874
  that review. This confirmation does NOT approve tool use. Effective settings persist
848
- with child results and appear in complete child source. Request/token caps may be
849
- lowered, not raised above 16 / 32,000; token usage is not exact billable accounting.
875
+ with child results and appear in complete child source. Runtime budget options
876
+ `--timeout`, `--calls`, `--tokens` and config/preset keys `timeout`, `max_model_calls`,
877
+ `max_tokens` are removed and rejected for new starts. Historical child records with
878
+ these budget fields remain readable; the fields are inert and never reapply a
879
+ budget or restart work. This removal does not remove the actual model's per-request
880
+ output token ceiling.
850
881
  `--fresh` omits canonical history/child entry inheritance, not mandatory parent
851
882
  validation/context or the shared workspace. Model/reasoning inherit by default; explicit overrides now use the actual adapter.
852
883
  Named presets now use explicit user configuration. Claw specialized
@@ -870,9 +901,12 @@ host native-tool overrides. Switching to a nonreasoning model disables inherited
870
901
  reasoning; unsupported positive choices fail visibly. Model switches omit inherited/
871
902
  transformed provider continuity and old reasoning from the CHILD copy, leaving parent
872
903
  provenance/history intact. Transformed images are validated; oversized switched-model
873
- contexts fail a conservative byte-based preflight with fresh/lower-output/larger-model
874
- guidance, not automatic summarization or exact token accounting. Parent model/options/
875
- settings/grants never change. Named presets now use explicit user configuration.
904
+ contexts use the same built-in text-token estimate as native compaction, rather
905
+ than comparing text bytes to token capacity. This is not exact tokenizer accounting.
906
+ Host-enabled compaction runs before forwarding the next model request; context that
907
+ cannot be safely compacted or fit still fails explicitly with original history
908
+ retained. Image/capability and actual output limits remain enforced. Parent
909
+ model/options/settings/grants never change. Named presets use explicit user configuration.
876
910
 
877
911
 
878
912
  ### Named child presets
@@ -889,15 +923,14 @@ using this descriptor shape:
889
923
  "instructions": "Review requested code; return findings with file locations.",
890
924
  "tools": ["filesystem", "current_time"],
891
925
  "inherit_context": false,
892
- "max_model_calls": 4,
893
- "max_tokens": 8000
926
+ "label": "Reviewer"
894
927
  }
895
928
  }
896
929
  }
897
930
  }
898
931
  ```
899
932
 
900
- Browse `/agents presets`, or use `/agents start --preset reviewer --tokens 6000 --
933
+ Browse `/agents presets`, or use `/agents start --preset reviewer --label Audit --
901
934
  TASK`. Explicit flags override template fields. Ctrl+P selects a template in a new
902
935
  child form, Ctrl+G adjusts the draft, and full expanded settings/task review still
903
936
  precedes execution. Selection itself makes no model request. Templates cannot encode
@@ -2622,3 +2655,68 @@ and widget layouts are removed. Native approval and recovery reviews remain host
2622
2655
  owned; they expose no plugin layout or editor/session-mutation authority. Core TUI
2623
2656
  overlays, transcript fullscreen, Unicode, clipping, cursor and tool-approval behavior
2624
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.
@@ -548,7 +548,8 @@ continuation silently reconnects, replays POSTs or expands configured disclosure
548
548
 
549
549
  ### Task planning and host read-only scope
550
550
 
551
- The builtin **`xdog-planning`** skill uses ordinary conversation or task documents
551
+ The builtin **`xdog-planning`** skill, supplied by `xdog-skills` (install the
552
+ `skills` extra), uses ordinary conversation or task documents
552
553
  for objectives, dependencies, acceptance criteria and evidence-backed progress.
553
554
  It does not create a separate plan database, inspector, execution mode or model
554
555
  loop. The former `/plan`, `PlanPanel` and `update_plan` UI/tool APIs are removed.
@@ -745,7 +746,7 @@ none of these interfaces grants tool permission or full Pi API compatibility.
745
746
 
746
747
  ### Supervised child agents
747
748
 
748
- `/agents start TASK` starts bounded read-only child work. `/agents start --inherit
749
+ `/agents start TASK` starts host-managed read-only child work. `/agents start --inherit
749
750
  TASK` inherits the current host policy; it does not copy approval grants or bypass
750
751
  read-only. Inspect with `/agents list` or `/agents inspect ID`; use `steer ID TEXT`,
751
752
  `follow-up ID TEXT`, `cancel ID`, `wait ID` and `close ID` under `/agents`.
@@ -754,10 +755,34 @@ recursively delegate through their parent's supervision tools.
754
755
 
755
756
  Children share the workspace, so coordinate conflicting writes. Context is copied
756
757
  at admission through a complete tool/result checkpoint. Model/options/tool execution
757
- mode are inherited. Defaults are three active children, 16 retained records,
758
- 120-second execution deadline, 16 model calls and a 32,000 reported-token stop
759
- threshold—not exact billing. Output limits are clamped; input accounting can
760
- overshoot on the final request. Cleanup/persistence may outlast the execution deadline.
758
+ mode are inherited. There is no fixed concurrent-child or retained-record count
759
+ limit, elapsed-time deadline, model-call cap or cumulative reported-token stop
760
+ threshold. The main Agent/host manages lifecycle with cancel/wait/close. Usage
761
+ counters remain reported usage, not exact billable accounting; actual model
762
+ output/context limits, permissions and message/input/image/per-file capacities
763
+ still apply. Complete history uses atomic segmented persistence instead of a
764
+ cumulative 512 KiB / 2,000-message execution cutoff; tool/result pairs are not
765
+ silently truncated.
766
+
767
+ Coding and Claw child factories explicitly enable the Agent's existing built-in
768
+ compaction policy through `AgentConfig(compaction=selected.compaction(child_stream))`
769
+ and provide `archive_compaction=store.archive_compaction` to the supervisor.
770
+ This does **not** change the generic Agent default: automatic compaction is off
771
+ unless explicitly configured. The selected helper uses the executing adapter's
772
+ real context/prompt/output capacity; unknown metadata, context capacity or output
773
+ reserve returns `None` (auto-compaction remains off), not a guessed fallback.
774
+ A host requiring automatic compaction must reject that case or explicitly supply
775
+ trusted capacity/reserve through native `CompactionConfig`.
776
+
777
+ With the policy enabled, one long tool turn can compact repeatedly at safe paired
778
+ boundaries. The supervisor waits for a durable full pre-compaction snapshot before
779
+ the native summary request starts. Archive, summary or stream-cleanup failure does
780
+ not commit a history cut, and cancellation settles owned writes/cleanup. The native
781
+ summary's per-request timeout/capacity checks remain; there is no replacement child
782
+ lifetime cap. Inspect shows the current retained context, possibly with summaries;
783
+ `children.store.compaction_archives(child_id)` reads full earlier snapshots without
784
+ replay. These child archives are separate from the parent session's `/tree`
785
+ compaction checkpoints.
761
786
 
762
787
  Each child has independent Coding approvals and extension workers/state. Parent
763
788
  validation/context hooks and current read-only/permission gates remain authoritative;
@@ -800,10 +825,10 @@ still uses silent no-UI answers to avoid borrowing its separate dialog reservati
800
825
  Complex extension forms are removed; basic child dialogs retain these ownership and cancellation checks.
801
826
 
802
827
 
803
- ### Child specialization and limits
828
+ ### Child specialization and protocol limits
804
829
 
805
830
  `/agents start --label Reviewer --instructions "Inspect only" --tools filesystem,current_time
806
- --fresh --timeout 60 --calls 4 --tokens 8000 -- TASK` specializes a child without
831
+ --fresh -- TASK` specializes a child without
807
832
  changing parent permissions. Options precede the task; `--` preserves a task that
808
833
  starts with flags. Plain tasks preserve quotes/newlines. `--tools none` gives the
809
834
  child no executable tools; otherwise selected names must exist in its inherited tool
@@ -812,11 +837,15 @@ fail visibly. Instructions append to, rather than replace, parent restrictions.
812
837
 
813
838
  In `/agents` press `n`, then Ctrl+G for settings JSON. Supported keys are `label`,
814
839
  `instructions`, `tools` (array or null for inherited tools), `inherit_context`,
815
- `timeout`, `max_model_calls` and `max_tokens`. Enter applies the settings draft only;
840
+ `model`, `thinking` and `preset`. Enter applies the settings draft only;
816
841
  start review requires every page to be painted before confirmation. Resize invalidates
817
842
  that review. This confirmation does NOT approve tool use. Effective settings persist
818
- with child results and appear in complete child source. Request/token caps may be
819
- lowered, not raised above 16 / 32,000; token usage is not exact billable accounting.
843
+ with child results and appear in complete child source. Runtime budget options
844
+ `--timeout`, `--calls`, `--tokens` and config/preset keys `timeout`, `max_model_calls`,
845
+ `max_tokens` are removed and rejected for new starts. Historical child records with
846
+ these budget fields remain readable; the fields are inert and never reapply a
847
+ budget or restart work. This removal does not remove the actual model's per-request
848
+ output token ceiling.
820
849
  `--fresh` omits canonical history/child entry inheritance, not mandatory parent
821
850
  validation/context or the shared workspace. Model/reasoning inherit by default; explicit overrides now use the actual adapter.
822
851
  Named presets now use explicit user configuration. Claw specialized
@@ -840,9 +869,12 @@ host native-tool overrides. Switching to a nonreasoning model disables inherited
840
869
  reasoning; unsupported positive choices fail visibly. Model switches omit inherited/
841
870
  transformed provider continuity and old reasoning from the CHILD copy, leaving parent
842
871
  provenance/history intact. Transformed images are validated; oversized switched-model
843
- contexts fail a conservative byte-based preflight with fresh/lower-output/larger-model
844
- guidance, not automatic summarization or exact token accounting. Parent model/options/
845
- settings/grants never change. Named presets now use explicit user configuration.
872
+ contexts use the same built-in text-token estimate as native compaction, rather
873
+ than comparing text bytes to token capacity. This is not exact tokenizer accounting.
874
+ Host-enabled compaction runs before forwarding the next model request; context that
875
+ cannot be safely compacted or fit still fails explicitly with original history
876
+ retained. Image/capability and actual output limits remain enforced. Parent
877
+ model/options/settings/grants never change. Named presets use explicit user configuration.
846
878
 
847
879
 
848
880
  ### Named child presets
@@ -859,15 +891,14 @@ using this descriptor shape:
859
891
  "instructions": "Review requested code; return findings with file locations.",
860
892
  "tools": ["filesystem", "current_time"],
861
893
  "inherit_context": false,
862
- "max_model_calls": 4,
863
- "max_tokens": 8000
894
+ "label": "Reviewer"
864
895
  }
865
896
  }
866
897
  }
867
898
  }
868
899
  ```
869
900
 
870
- Browse `/agents presets`, or use `/agents start --preset reviewer --tokens 6000 --
901
+ Browse `/agents presets`, or use `/agents start --preset reviewer --label Audit --
871
902
  TASK`. Explicit flags override template fields. Ctrl+P selects a template in a new
872
903
  child form, Ctrl+G adjusts the draft, and full expanded settings/task review still
873
904
  precedes execution. Selection itself makes no model request. Templates cannot encode
@@ -2592,3 +2623,68 @@ and widget layouts are removed. Native approval and recovery reviews remain host
2592
2623
  owned; they expose no plugin layout or editor/session-mutation authority. Core TUI
2593
2624
  overlays, transcript fullscreen, Unicode, clipping, cursor and tool-approval behavior
2594
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.2"
7
+ version = "2.4.4"
8
8
  description = "Interactive coding agent CLI"
9
9
  requires-python = ">=3.12"
10
10
  classifiers = [
@@ -22,15 +22,18 @@ 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.2",
26
- "xdog-agent>=2.4.2",
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.2",
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
+ [project.optional-dependencies]
35
+ skills = ["xdog-skills>=2.4.4"]
36
+
34
37
  [project.urls]
35
38
  Homepage = "https://xdog.942295.xyz"
36
39
  Repository = "https://github.com/litterzhang/xdog"
@@ -1,3 +1,3 @@
1
1
  """coding - Interactive coding agent CLI."""
2
2
 
3
- __version__ = "2.4.2"
3
+ __version__ = "2.4.4"
@@ -89,17 +89,19 @@ class CodingBackend:
89
89
  try:
90
90
  session = await asyncio.shield(task)
91
91
  except asyncio.CancelledError:
92
- session = await task
93
- session.dispose()
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 asyncio.wrap_future(runtime.close())
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
- await self._inbox.disconnect(peer)
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
- for row in pending:
306
- if row.ticket is None and not row.task.cancelling():
307
- row.task.cancel()
308
- for controller in {row.controller for row in pending}:
309
- await asyncio.wrap_future(controller.disconnect(peer.id))
310
- tasks = [row.task for row in pending if row.task is not asyncio.current_task()]
311
- if tasks:
312
- for task in tasks:
313
- if not task.done() and not task.cancelling():
314
- task.cancel()
315
- await asyncio.gather(*tasks, return_exceptions=True)
316
- for key, remote in tuple(self._remote.items()):
317
- if key[0] == peer.id:
318
- await remote.close()
319
- del self._remote[key]
320
- for identifier, (owner, runtime, server) in tuple(self._owned.items()):
321
- if owner == peer.id:
322
- await server.close()
323
- await asyncio.wrap_future(runtime.close())
324
- del self._owned[identifier]
325
- for key in tuple(self._refs):
326
- if key[0] == peer.id:
327
- del self._refs[key]
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
- self.closing = True
51
- if self.server is not None:
52
- self.server.close()
53
- for writer in tuple(self.writers):
54
- writer.close()
55
- if self.server is not None:
56
- # Python >=3.12 waits for client transports too; close them first.
57
- await self.server.wait_closed()
58
- self.server = None
59
- if self.tasks:
60
- await asyncio.gather(*tuple(self.tasks), return_exceptions=True)
61
- path = self.record.address
62
- if path.exists():
63
- info = path.lstat()
64
- if (stat.S_ISSOCK(info.st_mode) and info.st_uid == os.getuid()
65
- and (info.st_dev, info.st_ino) == self.identity):
66
- path.unlink()
67
- self.runtime.registry.remove(self.record)
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: