netizen-cli 0.10.0__tar.gz → 0.10.1__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 (212) hide show
  1. {netizen_cli-0.10.0/netizen_cli.egg-info → netizen_cli-0.10.1}/PKG-INFO +1 -1
  2. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/README.md +3 -4
  3. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/__init__.py +1 -1
  4. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/port_config.py +2 -19
  5. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/presentation.py +0 -34
  6. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/transport.py +4 -12
  7. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/web.py +2 -7
  8. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/bindings.py +9 -116
  9. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/controls.py +0 -32
  10. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/reply.py +0 -15
  11. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel_app.py +2 -20
  12. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_packages.py +5 -66
  13. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_services.py +0 -4
  14. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/codex_runtime.py +0 -50
  15. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/defaults/models.py +0 -4
  16. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/__init__.py +0 -2
  17. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/service.py +0 -23
  18. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/message_projection.py +11 -36
  19. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/projects.py +0 -7
  20. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/models.py +0 -4
  21. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/service.py +3 -17
  22. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/store.py +4 -12
  23. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/sdk_gap_adapter.py +10 -36
  24. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/turn_files.py +13 -68
  25. {netizen_cli-0.10.0 → netizen_cli-0.10.1/netizen_cli.egg-info}/PKG-INFO +1 -1
  26. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/pyproject.toml +1 -1
  27. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_bindings.py +58 -48
  28. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_channel_app.py +21 -24
  29. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_packages.py +41 -62
  30. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_codex_runtime.py +85 -58
  31. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_deployment.py +47 -18
  32. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_main.py +4 -1
  33. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_project_delete_channel.py +1 -1
  34. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_project_delete_runtime.py +3 -3
  35. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_project_deletion_storage.py +3 -5
  36. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_question_channel.py +5 -5
  37. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_question_target_parity.py +3 -3
  38. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_quoted_context.py +39 -21
  39. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_runtime_thread_naming.py +1 -1
  40. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_scope_matrix.py +4 -0
  41. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_service.py +67 -12
  42. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_scheduled_runtime.py +2 -1
  43. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedules_storage.py +12 -8
  44. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_sdk_gap_adapter.py +9 -5
  45. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_session_settings.py +2 -1
  46. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_settings_projects.py +9 -5
  47. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_turn_files.py +37 -175
  48. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_turn_patch_statistics.py +28 -8
  49. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/MANIFEST.in +0 -0
  50. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/_build.py +0 -0
  51. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/config.example.yaml +0 -0
  52. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/__main__.py +0 -0
  53. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/__init__.py +0 -0
  54. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/auth.py +0 -0
  55. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/errors.py +0 -0
  56. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/queries.py +0 -0
  57. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/static/admin.css +0 -0
  58. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/static/admin.js +0 -0
  59. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/admin/static/index.html +0 -0
  60. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/builtin_skills.py +0 -0
  61. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/__init__.py +0 -0
  62. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/callbacks.py +0 -0
  63. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/defaults.py +0 -0
  64. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/model_info.py +0 -0
  65. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/questions.py +0 -0
  66. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cards/scheduled.py +0 -0
  67. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/__init__.py +0 -0
  68. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/completion_mentions.py +0 -0
  69. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/input_preparation.py +0 -0
  70. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/messages.py +0 -0
  71. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/ports.py +0 -0
  72. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/question_inputs.py +0 -0
  73. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/reactions.py +0 -0
  74. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/reply_presenter.py +0 -0
  75. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/channel/topics.py +0 -0
  76. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli.py +0 -0
  77. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_data.py +0 -0
  78. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_setup.py +0 -0
  79. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_update.py +0 -0
  80. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_update_restore.py +0 -0
  81. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/cli_update_worker.py +0 -0
  82. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/completion_mention.py +0 -0
  83. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/database_migrations.py +0 -0
  84. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/defaults/__init__.py +0 -0
  85. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/defaults/service.py +0 -0
  86. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/defaults/store.py +0 -0
  87. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/deployment/__init__.py +0 -0
  88. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/deployment/restart_worker.py +0 -0
  89. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/deployment/update_executor.py +0 -0
  90. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/deployment/update_protocol.py +0 -0
  91. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/domain.py +0 -0
  92. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/error_messages.py +0 -0
  93. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/experience.py +0 -0
  94. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/feishu_app_onboarding.py +0 -0
  95. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/feishu_app_permissions.py +0 -0
  96. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/git_status.py +0 -0
  97. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/image_inputs.py +0 -0
  98. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/instance.py +0 -0
  99. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/lark_app.py +0 -0
  100. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/main.py +0 -0
  101. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/blocking_io.py +0 -0
  102. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/chat_labels.py +0 -0
  103. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/coordination.py +0 -0
  104. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/management/updates.py +0 -0
  105. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/markdown_images.py +0 -0
  106. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/message_content.py +0 -0
  107. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/message_history.py +0 -0
  108. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/message_preparation.py +0 -0
  109. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/migrations/__init__.py +0 -0
  110. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/migrations/schema.py +0 -0
  111. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/migrations/v14.py +0 -0
  112. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/model_settings.py +0 -0
  113. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/package_resources.py +0 -0
  114. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/prompt_projection.py +0 -0
  115. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/quoted_context.py +0 -0
  116. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/result_images.py +0 -0
  117. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/runtime/__init__.py +0 -0
  118. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/runtime/contracts.py +0 -0
  119. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/runtime/name_writes.py +0 -0
  120. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/runtime/thread_naming.py +0 -0
  121. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/__init__.py +0 -0
  122. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/mcp.py +0 -0
  123. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/schedules/scheduler.py +0 -0
  124. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/service_launcher.py +0 -0
  125. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/session_settings.py +0 -0
  126. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/settings.py +0 -0
  127. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/skill_references.py +0 -0
  128. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/terminal_cleanup.py +0 -0
  129. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/turn_activity.py +0 -0
  130. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/turn_patch_children.py +0 -0
  131. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/turn_plan_observer.py +0 -0
  132. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli/user_questions.py +0 -0
  133. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli.egg-info/SOURCES.txt +0 -0
  134. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli.egg-info/dependency_links.txt +0 -0
  135. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli.egg-info/entry_points.txt +0 -0
  136. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli.egg-info/requires.txt +0 -0
  137. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/netizen_cli.egg-info/top_level.txt +0 -0
  138. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/setup.cfg +0 -0
  139. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/skills/netizen-lark/SKILL.md +0 -0
  140. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/skills/netizen-user-guide/SKILL.md +0 -0
  141. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/skills/netizen-user-guide/references/user-guide.md +0 -0
  142. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_admin_update_executor_probe.py +0 -0
  143. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_binding_scheduled_channel.py +0 -0
  144. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cards.py +0 -0
  145. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_channel_fixtures.py +0 -0
  146. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_channel_input_preparation.py +0 -0
  147. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_check_sdk.py +0 -0
  148. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli.py +0 -0
  149. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_data.py +0 -0
  150. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_distribution.py +0 -0
  151. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_integration.py +0 -0
  152. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_packaging.py +0 -0
  153. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_services.py +0 -0
  154. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_setup.py +0 -0
  155. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_cli_update.py +0 -0
  156. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_codex_sdk_capabilities.py +0 -0
  157. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_completion_mention_cards.py +0 -0
  158. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_completion_mentions.py +0 -0
  159. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_completion_topic_delivery.py +0 -0
  160. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_database_migrations.py +0 -0
  161. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_defaults_cards.py +0 -0
  162. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_defaults_channel.py +0 -0
  163. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_defaults_runtime.py +0 -0
  164. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_documentation_links.py +0 -0
  165. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_domain_experience.py +0 -0
  166. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_error_messages.py +0 -0
  167. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_feishu_app_onboarding.py +0 -0
  168. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_feishu_app_permissions.py +0 -0
  169. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_file_pagination.py +0 -0
  170. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_git_status.py +0 -0
  171. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_image_inputs.py +0 -0
  172. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_lark_app.py +0 -0
  173. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_lark_sdk_contract.py +0 -0
  174. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_markdown_images.py +0 -0
  175. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_message_content.py +0 -0
  176. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_message_history.py +0 -0
  177. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_message_material_inputs.py +0 -0
  178. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_message_preparation.py +0 -0
  179. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_migration_schema_validation.py +0 -0
  180. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_model_info_cards.py +0 -0
  181. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_model_settings.py +0 -0
  182. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_name_writes.py +0 -0
  183. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_child_files.py +0 -0
  184. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_feishu_completion_mention.py +0 -0
  185. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_feishu_turn_file_card.py +0 -0
  186. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_python_sdk.py +0 -0
  187. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_scheduled_tasks.py +0 -0
  188. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_sdk_completion_race.py +0 -0
  189. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_probe_thread_naming.py +0 -0
  190. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_prompt_projection.py +0 -0
  191. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_question_cards.py +0 -0
  192. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_release_script.py +0 -0
  193. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_repository_hygiene.py +0 -0
  194. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_result_images.py +0 -0
  195. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_retired_deployment.py +0 -0
  196. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_card_retry.py +0 -0
  197. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_cards.py +0 -0
  198. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_mcp.py +0 -0
  199. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_schedule_run_now.py +0 -0
  200. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_scheduled_channel.py +0 -0
  201. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_scheduler.py +0 -0
  202. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_scheduler_presenter.py +0 -0
  203. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_service_launcher.py +0 -0
  204. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_session_defaults.py +0 -0
  205. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_terminal_cleanup.py +0 -0
  206. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_thread_naming.py +0 -0
  207. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_turn_activity.py +0 -0
  208. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_turn_patch_children.py +0 -0
  209. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_turn_plan_observer.py +0 -0
  210. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_update_executor.py +0 -0
  211. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_user_guide_skill.py +0 -0
  212. {netizen_cli-0.10.0 → netizen_cli-0.10.1}/tests/test_user_questions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netizen-cli
3
- Version: 0.10.0
3
+ Version: 0.10.1
4
4
  Summary: Use native Codex threads through a Feishu Channel.
5
5
  Requires-Python: <3.15,>=3.11
6
6
  Requires-Dist: h11==0.16.0
@@ -69,8 +69,8 @@ Linux 注销后常驻需要 linger;macOS 服务随桌面登录启动、注销
69
69
 
70
70
  ### 2. 安装 CLI 并创建实例
71
71
 
72
- 此分支改为普通 Python CLI,尚未发布到 PyPI;以下为新版使用方式,不表示旧 Release
73
- 已具备这些命令。开发安装见[贡献指南](docs/CONTRIBUTING.md)。发行后在选定环境安装:
72
+ 在选定 Python 环境从 PyPI 安装 `netizen-cli`。源码开发安装见
73
+ [贡献指南](docs/CONTRIBUTING.md)。
74
74
 
75
75
  ```sh
76
76
  python -m pip install netizen-cli
@@ -91,8 +91,7 @@ setup 准备配置、飞书授权和实例数据并注册服务,不默认启
91
91
 
92
92
  日常维护用 `netizen update` 更新当前环境并恢复原来运行的实例;它不接受 --root。
93
93
  `netizen remove --root ...` 默认保留数据,--purge 才清理精确范围,-y 只省略确认。
94
- 完整流程、失败边界、跨环境切换和卸载见 [CLI 安装与维护](docs/cli.md)。旧安装手工转换,
95
- 不提供自动旧布局迁移,不要直接对现有旧实例执行新版清理命令。
94
+ 完整流程、失败边界、跨环境切换和卸载见 [CLI 安装与维护](docs/cli.md)。
96
95
 
97
96
  ### 3. 在飞书开始第一次对话
98
97
 
@@ -1,3 +1,3 @@
1
1
  """Netizen: a thin Feishu Channel for native Codex Threads."""
2
2
 
3
- __version__ = "0.10.0"
3
+ __version__ = "0.10.1"
@@ -1,4 +1,4 @@
1
- """Narrow atomic port writes for explicit installation and first startup."""
1
+ """Atomic persistence of the Admin port allocated during first startup."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -56,7 +56,7 @@ def persist_admin_port(snapshot: ConfigFileSnapshot, port: int) -> None:
56
56
  """Preserve all YAML values and refuse a detected concurrent human edit.
57
57
 
58
58
  The caller retains its listening socket and instance lifetime lock. This
59
- deliberately does not acquire the installer lock (the installer may still
59
+ deliberately does not acquire the CLI maintenance lock (the CLI may still
60
60
  be waiting for this startup). Only the previously absent port is added.
61
61
  """
62
62
 
@@ -75,23 +75,6 @@ def persist_admin_port(snapshot: ConfigFileSnapshot, port: int) -> None:
75
75
  _write_configuration(snapshot, loaded)
76
76
 
77
77
 
78
- def set_admin_port(path: Path, port: int) -> None:
79
- """Apply an explicit installer choice, even if Admin is currently disabled."""
80
-
81
- _validate_port(port)
82
- snapshot = ConfigFileSnapshot.read(path)
83
- loaded = yaml.safe_load(snapshot.content)
84
- if not isinstance(loaded, dict):
85
- raise AdminPortConfigurationError("configuration root must be a mapping")
86
- values = loaded.setdefault("adminWeb", {})
87
- if not isinstance(values, dict):
88
- raise AdminPortConfigurationError("adminWeb must be a mapping")
89
- values = dict(values)
90
- loaded["adminWeb"] = values
91
- values["port"] = port
92
- _write_configuration(snapshot, loaded)
93
-
94
-
95
78
  def _validate_port(port: int) -> None:
96
79
  if isinstance(port, bool) or not isinstance(port, int) or not 1 <= port <= 65535:
97
80
  raise AdminPortConfigurationError("Admin port must be from 1 to 65535")
@@ -17,40 +17,6 @@ from ..runtime.contracts import (
17
17
  from ..management import BindingStatusProjection, ChatLabel
18
18
 
19
19
 
20
- def _release_check_message(code: str | None) -> str | None:
21
- if code is None:
22
- return None
23
- return {
24
- "release_rate_limited": "GitHub 更新查询已触发限流,请稍后重试。",
25
- "release_access_denied": (
26
- "更新查询被拒绝(HTTP 403)。请检查服务所在机器的网络访问策略或代理配置;"
27
- "若持续出现,请联系维护者。"
28
- ),
29
- "release_not_found": (
30
- "未找到可访问的官方发布版本(HTTP 404)。请稍后重试;"
31
- "若持续出现,请联系维护者检查仓库与 Release 状态。"
32
- ),
33
- "release_service_unavailable": (
34
- "更新服务暂时异常(HTTP 5xx)。请稍后重新检查。"
35
- ),
36
- "release_http_error": (
37
- "更新查询收到异常 HTTP 响应。请稍后重试;"
38
- "若持续出现,请联系维护者检查更新接口或网络代理。"
39
- ),
40
- "release_check_timeout": (
41
- "查询 GitHub 更新服务超时。请稍后重试;"
42
- "若持续出现,请检查服务所在机器的网络或代理配置。"
43
- ),
44
- "release_network_error": (
45
- "访问 GitHub 更新服务时发生网络错误。请检查服务所在机器的网络、代理和 HTTPS 证书配置后再试。"
46
- ),
47
- "release_invalid_response": (
48
- "官方更新信息格式异常,或发布资产不完整、未通过校验。"
49
- "请稍后重试;若持续出现,请联系维护者检查 Release。"
50
- ),
51
- }.get(code, "检查更新失败,原因暂未识别。请稍后重试;若持续出现,请联系维护者。")
52
-
53
-
54
20
  def _chat_open_url(chat: ChatLabel) -> str:
55
21
  if chat.chat_mode == "p2p" and chat.p2p_target_open_id is not None:
56
22
  query = urlencode({"openId": chat.p2p_target_open_id})
@@ -112,7 +112,6 @@ class _ClientDisconnected(Exception):
112
112
  class _Connection:
113
113
  writer: asyncio.StreamWriter
114
114
  accepted_at: float
115
- task: asyncio.Task[None] | None = None
116
115
  handler_task: asyncio.Task[Response] | None = None
117
116
 
118
117
 
@@ -350,7 +349,6 @@ class AdminHttpTransport:
350
349
  task = self._owned_loop().create_task(
351
350
  self._serve_connection(connection, reader)
352
351
  )
353
- connection.task = task
354
352
  self._track_task(task, self._connection_tasks)
355
353
 
356
354
  async def _serve_connection(
@@ -365,17 +363,15 @@ class AdminHttpTransport:
365
363
  h11.SERVER,
366
364
  max_incomplete_event_size=MAX_HEADER_SECTION_BYTES,
367
365
  )
368
- pending = b""
369
366
  first_request = True
370
367
 
371
368
  try:
372
369
  while not self._closing:
373
370
  request_id = secrets.token_hex(16)
374
371
  try:
375
- request, pending = await self._read_request(
372
+ request = await self._read_request(
376
373
  reader=reader,
377
374
  parser=parser,
378
- pending=pending,
379
375
  first_request=first_request,
380
376
  accepted_at=connection.accepted_at,
381
377
  peer=peer,
@@ -486,7 +482,6 @@ class AdminHttpTransport:
486
482
  parser.start_next_cycle()
487
483
  except h11.LocalProtocolError:
488
484
  return
489
- pending = b""
490
485
  except asyncio.CancelledError:
491
486
  handler = connection.handler_task
492
487
  if handler is not None and not handler.done():
@@ -505,19 +500,17 @@ class AdminHttpTransport:
505
500
  *,
506
501
  reader: asyncio.StreamReader,
507
502
  parser: h11.Connection,
508
- pending: bytes,
509
503
  first_request: bool,
510
504
  accepted_at: float,
511
505
  peer: Address,
512
506
  sockname: Address,
513
507
  request_id: str,
514
- ) -> tuple[Request, bytes]:
508
+ ) -> Request:
515
509
  loop = self._owned_loop()
510
+ pending = b""
516
511
 
517
512
  if first_request:
518
513
  header_deadline = accepted_at + HEADER_TIMEOUT_SECONDS
519
- elif pending:
520
- header_deadline = loop.time() + HEADER_TIMEOUT_SECONDS
521
514
  else:
522
515
  try:
523
516
  first_byte = await asyncio.wait_for(
@@ -578,7 +571,7 @@ class AdminHttpTransport:
578
571
  # entered are pipelining, including a same-write second request.
579
572
  raise _RequestRejected(400, "pipelined_request")
580
573
 
581
- request = Request(
574
+ return Request(
582
575
  method=event.method,
583
576
  target=event.target,
584
577
  http_version=event.http_version,
@@ -588,7 +581,6 @@ class AdminHttpTransport:
588
581
  sockname=sockname,
589
582
  request_id=request_id,
590
583
  )
591
- return request, b""
592
584
 
593
585
  async def _read_header_section(
594
586
  self,
@@ -38,7 +38,6 @@ from .presentation import (
38
38
  _chat_open_url,
39
39
  _jsonable,
40
40
  _project_result,
41
- _release_check_message,
42
41
  _release_disposition_message,
43
42
  _runtime_binding_json,
44
43
  _runtime_side_json,
@@ -127,7 +126,6 @@ from ..management import (
127
126
  CurrentSideTarget,
128
127
  ExactBindingTarget,
129
128
  InstanceManagementService,
130
- NativeCatalogInconsistent,
131
129
  NativeThreadMissing,
132
130
  ProjectDeletionResult,
133
131
  RuntimePrecondition,
@@ -542,9 +540,9 @@ class AdminWebApplication:
542
540
  self, context: _RequestContext, status: dict[str, Any]
543
541
  ) -> Response:
544
542
  payload = dict(status)
545
- checking_error_code = payload.pop("checkingErrorCode")
543
+ payload.pop("checkingErrorCode")
546
544
  payload["message"] = "程序更新属于 Python 环境级操作,请在对应环境运行 netizen update;管理页只重启当前实例。"
547
- payload["checkingError"] = _release_check_message(checking_error_code)
545
+ payload["checkingError"] = None
548
546
  actions: dict[str, object] = {
549
547
  "check": None,
550
548
  "install": None,
@@ -2608,10 +2606,8 @@ def _runtime_precondition(grant: object) -> RuntimePrecondition:
2608
2606
 
2609
2607
 
2610
2608
  _UPDATE_HTTP_ERRORS = {
2611
- "invalid_update_target": (400, "invalid_update_target", "升级目标无效。"),
2612
2609
  "update_unsupported": (409, "update_unsupported", "请在对应 Python 环境运行 netizen update。"),
2613
2610
  "restart_unsupported": (409, "restart_unsupported", "仅绑定当前 Python 环境的受管实例支持 Admin 重启。"),
2614
- "update_target_changed": (409, "update_target_changed", "升级目标已变化,请重新检查更新。"),
2615
2611
  "update_busy": (409, "update_busy", "另一个安装或维护操作正在执行,请稍后查看结果。"),
2616
2612
  "update_state_unavailable": (
2617
2613
  503, "update_state_unavailable", "维护状态无法确认,请检查实例维护记录。",
@@ -2693,7 +2689,6 @@ def _map_error(error: BaseException) -> AdminWebError | None:
2693
2689
  BlockingIOResultUnknown,
2694
2690
  BlockingIODrainTimeout,
2695
2691
  BlockingIOShutdownTimeout,
2696
- NativeCatalogInconsistent,
2697
2692
  RuntimeClosed,
2698
2693
  ThreadCatalogError,
2699
2694
  ThreadLifecycleStateUnknown,
@@ -872,40 +872,6 @@ class BindingStore:
872
872
  )
873
873
  return tuple(self.get_side_topic(row["side_id"]) for row in rows)
874
874
 
875
- def create_binding(
876
- self,
877
- *,
878
- scope: FeishuScope,
879
- project_alias: str,
880
- creator_id: str,
881
- turn_settings: BindingTurnSettings | None = None,
882
- task_feedback: BindingTaskFeedback = BindingTaskFeedback(),
883
- message_context_mode: MentionContextMode = MentionContextMode.CURRENT_ONLY,
884
- context_anchor: MessageContextAnchor | None = None,
885
- ) -> ThreadBinding:
886
- """Compatibility entry point for older callers.
887
-
888
- Production ingress should use :meth:`create_channel_binding`, whose
889
- Project check is unconditional. Existing direct callers
890
- that have an entirely empty Project registry retain the historical
891
- construction seam; once any Project exists, this method applies the
892
- same enabled-Project requirement as production.
893
- """
894
-
895
- return self._create_binding(
896
- scope=scope,
897
- project_alias=project_alias,
898
- creator_id=creator_id,
899
- turn_settings=turn_settings,
900
- task_feedback=task_feedback,
901
- message_context_mode=message_context_mode,
902
- context_anchor=context_anchor,
903
- expected_project_revision=None,
904
- activate=True,
905
- allow_scope_insert=True,
906
- allow_empty_project_registry=True,
907
- )
908
-
909
875
  def create_channel_binding(
910
876
  self,
911
877
  *,
@@ -933,7 +899,6 @@ class BindingStore:
933
899
  expected_project_revision=expected_project_revision,
934
900
  activate=True,
935
901
  allow_scope_insert=True,
936
- allow_empty_project_registry=False,
937
902
  )
938
903
 
939
904
  def create_admin_binding(
@@ -962,7 +927,6 @@ class BindingStore:
962
927
  expected_project_revision=expected_project_revision,
963
928
  activate=activate,
964
929
  allow_scope_insert=False,
965
- allow_empty_project_registry=False,
966
930
  )
967
931
 
968
932
  def _create_binding(
@@ -978,7 +942,6 @@ class BindingStore:
978
942
  expected_project_revision: int | None,
979
943
  activate: bool,
980
944
  allow_scope_insert: bool,
981
- allow_empty_project_registry: bool,
982
945
  scheduled_run_id: str | None = None,
983
946
  ) -> ThreadBinding:
984
947
  if not project_alias or not creator_id:
@@ -1057,22 +1020,15 @@ class BindingStore:
1057
1020
  (project_alias,),
1058
1021
  ).fetchone()
1059
1022
  self.require_project_not_deleting(project_alias)
1060
- if project_row is None and allow_empty_project_registry:
1061
- any_project = self._connection.execute(
1062
- "SELECT 1 FROM projects LIMIT 1"
1063
- ).fetchone()
1064
- if any_project is not None:
1065
- raise ProjectNotFound(project_alias)
1066
- elif project_row is None:
1023
+ if project_row is None:
1067
1024
  raise ProjectNotFound(project_alias)
1068
- if project_row is not None:
1069
- if not bool(project_row["enabled"]):
1070
- raise ProjectDisabled(project_alias)
1071
- if (
1072
- expected_project_revision is not None
1073
- and project_row["revision"] != expected_project_revision
1074
- ):
1075
- raise ProjectRevisionConflict(project_alias)
1025
+ if not bool(project_row["enabled"]):
1026
+ raise ProjectDisabled(project_alias)
1027
+ if (
1028
+ expected_project_revision is not None
1029
+ and project_row["revision"] != expected_project_revision
1030
+ ):
1031
+ raise ProjectRevisionConflict(project_alias)
1076
1032
 
1077
1033
  self._connection.execute(
1078
1034
  """
@@ -1133,7 +1089,7 @@ class BindingStore:
1133
1089
  task_feedback=session_settings.task_feedback,
1134
1090
  message_context_mode=session_settings.message_context_mode,
1135
1091
  context_anchor=context_anchor, expected_project_revision=None, activate=True,
1136
- allow_scope_insert=True, allow_empty_project_registry=False,
1092
+ allow_scope_insert=True,
1137
1093
  scheduled_run_id=run_id,
1138
1094
  )
1139
1095
 
@@ -1498,62 +1454,6 @@ class BindingStore:
1498
1454
  )
1499
1455
  return self.get(binding_id)
1500
1456
 
1501
- def deactivate(self, *, scope_key: str, binding_id: str) -> ThreadBinding:
1502
- """Clear the active pointer only when it still targets this Binding."""
1503
-
1504
- with self._transaction():
1505
- row = self._connection.execute(
1506
- "SELECT active_binding_id FROM scopes WHERE scope_key = ?",
1507
- (scope_key,),
1508
- ).fetchone()
1509
- if row is None or row["active_binding_id"] != binding_id:
1510
- raise BindingConflict("Binding is no longer active in this Scope")
1511
- owner = self._connection.execute(
1512
- "SELECT scope_key FROM bindings WHERE binding_id = ?",
1513
- (binding_id,),
1514
- ).fetchone()
1515
- if owner is None or owner["scope_key"] != scope_key:
1516
- raise BindingNotFound(binding_id)
1517
- self._connection.execute(
1518
- """
1519
- UPDATE scopes
1520
- SET active_binding_id = NULL, updated_at = ?
1521
- WHERE scope_key = ? AND active_binding_id = ?
1522
- """,
1523
- (_now(), scope_key, binding_id),
1524
- )
1525
- return self.get(binding_id)
1526
-
1527
- def deactivate_if_active(
1528
- self,
1529
- *,
1530
- scope_key: str,
1531
- binding_id: str,
1532
- ) -> ThreadBinding:
1533
- """Clear this Binding's Scope pointer when it is still current.
1534
-
1535
- Exact management operations may archive an inactive Binding. They
1536
- must still validate ownership, but must not disturb the Scope's actual
1537
- current pointer merely because another Binding was the mutation target.
1538
- """
1539
-
1540
- with self._transaction():
1541
- owner = self._connection.execute(
1542
- "SELECT scope_key FROM bindings WHERE binding_id = ?",
1543
- (binding_id,),
1544
- ).fetchone()
1545
- if owner is None or owner["scope_key"] != scope_key:
1546
- raise BindingNotFound(binding_id)
1547
- self._connection.execute(
1548
- """
1549
- UPDATE scopes
1550
- SET active_binding_id = NULL, updated_at = ?
1551
- WHERE scope_key = ? AND active_binding_id = ?
1552
- """,
1553
- (_now(), scope_key, binding_id),
1554
- )
1555
- return self.get(binding_id)
1556
-
1557
1457
  def delete_binding(self, binding_id: str) -> ThreadBinding:
1558
1458
  """Delete one Binding and clear its Scope pointer in one transaction."""
1559
1459
 
@@ -2283,13 +2183,6 @@ class BindingStore:
2283
2183
  return root_record
2284
2184
  return None
2285
2185
 
2286
- def list_side_topics(self) -> list[SideTopicRecord]:
2287
- with self._lock:
2288
- rows = self._connection.execute(
2289
- _SIDE_TOPIC_SELECT + " ORDER BY created_at, side_id"
2290
- ).fetchall()
2291
- return [_side_topic(row) for row in rows]
2292
-
2293
2186
  async def query_bindings(
2294
2187
  self,
2295
2188
  *,
@@ -2178,38 +2178,6 @@ def _decode_project_management_form(
2178
2178
  )
2179
2179
 
2180
2180
 
2181
- def _project_row(
2182
- project: Project,
2183
- controls: list[dict[str, Any]],
2184
- *,
2185
- status: str,
2186
- ) -> dict[str, Any]:
2187
- return {
2188
- "tag": "column_set",
2189
- "flex_mode": "none",
2190
- "background_style": "grey-50",
2191
- "margin": "0 0 8px 0",
2192
- "columns": [
2193
- {
2194
- "tag": "column",
2195
- "width": "weighted",
2196
- "weight": 5,
2197
- "padding": "8px",
2198
- "elements": [
2199
- _plain(f"{project.alias} · {status}\n{project.cwd}"),
2200
- ],
2201
- },
2202
- {
2203
- "tag": "column",
2204
- "width": "auto",
2205
- "vertical_align": "center",
2206
- "padding": "8px",
2207
- "elements": controls,
2208
- },
2209
- ],
2210
- }
2211
-
2212
-
2213
2181
  def _archived_session_row(
2214
2182
  *,
2215
2183
  scope: FeishuScope,
@@ -571,21 +571,6 @@ def turn_progress_card(
571
571
  )
572
572
 
573
573
 
574
- def _turn_file_manifest(
575
- files: tuple[TurnFile, ...],
576
- ) -> tuple[TurnFileManifestItem, ...]:
577
- return tuple(
578
- TurnFileManifestItem(
579
- path=str(turn_file.resolved_path),
580
- label=turn_file.display_path,
581
- additions=turn_file.additions,
582
- deletions=turn_file.deletions,
583
- deleted=turn_file.deleted,
584
- )
585
- for turn_file in files
586
- )
587
-
588
-
589
574
  def _turn_progress_manifest(
590
575
  snapshot: _TurnActivitySnapshotLike,
591
576
  ) -> TurnProgressManifest:
@@ -91,7 +91,7 @@ from .channel.completion_mentions import send_completion_mention
91
91
  from .channel.input_preparation import MessageInputPreparer
92
92
  from .channel.question_inputs import CardAnswerConversation, CardAnswerOrigin, card_answer_sender
93
93
  from .channel.ports import ReplyChannel
94
- from .channel.topics import TopicPublishError, send_topic_message, validate_topic_message
94
+ from .channel.topics import TopicPublishError, send_topic_message
95
95
  from .cards.scheduled import (
96
96
  decode_schedule_action,
97
97
  is_schedule_card_action,
@@ -652,10 +652,6 @@ class _SentMessage:
652
652
  parent_id: str | None
653
653
 
654
654
 
655
- # Compatibility construction seam retained for focused ordinary-Turn tests.
656
- _ProgressCardController = _ReplyCardPresenter
657
-
658
-
659
655
  class ChannelApplication:
660
656
  def __init__(
661
657
  self,
@@ -687,7 +683,7 @@ class ChannelApplication:
687
683
  self._scope_coordinator = management.scope_coordinator
688
684
  self._scheduled_completions: set[str] = set()
689
685
  self._reactions = _ReactionController(channel)
690
- self._progress_cards = _ProgressCardController(channel, runtime)
686
+ self._progress_cards = _ReplyCardPresenter(channel, runtime)
691
687
  runtime.set_completion_handler(self.handle_completion)
692
688
  runtime.set_question_handler(self.handle_questions)
693
689
 
@@ -6338,20 +6334,6 @@ def _side_reply_target(
6338
6334
  )
6339
6335
 
6340
6336
 
6341
- def _validated_sent_message(
6342
- result: object,
6343
- *,
6344
- expected_chat_id: str,
6345
- ) -> _SentMessage:
6346
- try:
6347
- sent = validate_topic_message(result, expected_chat_id)
6348
- except TopicPublishError as error:
6349
- raise SideTopicCreateFailed("Side " + str(error)) from error
6350
- return _SentMessage(
6351
- sent.message_id, sent.chat_id, sent.thread_id, sent.root_id, sent.parent_id,
6352
- )
6353
-
6354
-
6355
6337
  def _is_feishu_card_action_lock(result: object) -> bool:
6356
6338
  if getattr(result, "success", None) is not False:
6357
6339
  return False
@@ -150,66 +150,6 @@ def _canonical_name(value: str) -> str:
150
150
  return re.sub(r"[-_.]+", "-", value).lower()
151
151
 
152
152
 
153
- def _config_paths(backend: str, prefix: Path, env: Mapping[str, str]) -> set[Path]:
154
- """Bounded documented config locations, not a replacement config parser."""
155
- home = Path.home()
156
- config_home = Path(env.get("XDG_CONFIG_HOME") or home / ".config")
157
- if backend == "pip":
158
- paths = {home / ".pip/pip.conf", config_home / "pip/pip.conf", prefix / "pip.conf"}
159
- paths.add(Path("/etc/pip.conf"))
160
- for root in (env.get("XDG_CONFIG_DIRS") or "/etc/xdg").split(os.pathsep):
161
- paths.add(Path(root) / "pip/pip.conf")
162
- if sys.platform == "darwin":
163
- # pip 26.2 also honors XDG data paths on macOS. Keep legacy and
164
- # fallback locations in this conservative check across pip versions.
165
- paths.update({Path("/Library/Application Support/pip/pip.conf"),
166
- home / "Library/Application Support/pip/pip.conf",
167
- home / ".config/pip/pip.conf"})
168
- if env.get("XDG_DATA_HOME"):
169
- paths.add(Path(env["XDG_DATA_HOME"]) / "pip/pip.conf")
170
- for root in (env.get("XDG_DATA_DIRS") or "").split(os.pathsep):
171
- if root:
172
- paths.add(Path(root) / "pip/pip.conf")
173
- else:
174
- paths = {config_home / "uv/uv.toml", Path("/etc/uv/uv.toml")}
175
- return paths
176
-
177
-
178
- def _check_tool_config(backend: str, prefix: Path, env: Mapping[str, str]) -> None:
179
- variable = "PIP_CONFIG_FILE" if backend == "pip" else "UV_CONFIG_FILE"
180
- explicit = env.get(variable)
181
- # pip explicitly documents the null device as disabling all configuration.
182
- if backend == "pip" and explicit == os.devnull:
183
- return
184
- if backend != "pip" and env.get("UV_NO_CONFIG", "").lower() in ("1", "true", "yes"):
185
- return
186
- if explicit:
187
- raise PackageUpdateError(
188
- f"{variable} selects custom package configuration; automatic update cannot verify "
189
- "its target settings. Use the owning package manager manually."
190
- )
191
- existing = sorted(str(p) for p in _config_paths(backend, prefix, env) if p.exists())
192
- if backend != "pip":
193
- for directory in (Path.cwd(), *Path.cwd().parents):
194
- config = directory / "uv.toml"
195
- if config.exists():
196
- existing.append(str(config))
197
- project = directory / "pyproject.toml"
198
- if project.is_file():
199
- try:
200
- settings = tomllib.loads(project.read_text())
201
- except (OSError, ValueError) as exc:
202
- raise PackageUpdateError(f"Cannot verify project configuration {project}; update manually.") from exc
203
- if "uv" in settings.get("tool", {}):
204
- existing.append(str(project))
205
- if existing:
206
- raise PackageUpdateError(
207
- "Custom package configuration requires manual update in this release: "
208
- + ", ".join(existing)
209
- + ". Automatic update does not silently ignore indexes, constraints or target settings."
210
- )
211
-
212
-
213
153
  def _check_environment_options(backend: str, env: Mapping[str, str]) -> None:
214
154
  if backend == "pip":
215
155
  denied_values = (
@@ -294,7 +234,7 @@ def _uv_executable(env: Mapping[str, str]) -> str:
294
234
 
295
235
 
296
236
  def _uv_directory(uv: str, kind: str, env: Mapping[str, str], cwd: Path) -> Path:
297
- result = _run([uv, "--no-config", kind, "dir"], env=env, cwd=cwd)
237
+ result = _run([uv, kind, "dir"], env=env, cwd=cwd)
298
238
  _require_success(result, f"uv {kind}-directory query")
299
239
  raw = result.stdout.strip()
300
240
  if not raw or "\n" in raw or not Path(raw).is_absolute():
@@ -317,7 +257,7 @@ def _reject_uv_cache_environment(prefix: Path, cache_root: Path | None = None) -
317
257
 
318
258
 
319
259
  def _uv_context(uv: str, env: Mapping[str, str], cwd: Path) -> tuple[str, Path, Path]:
320
- result = _run([uv, "--no-config", "self", "version", "--output-format", "json"], env=env, cwd=cwd)
260
+ result = _run([uv, "self", "version", "--output-format", "json"], env=env, cwd=cwd)
321
261
  _require_success(result, "uv version query")
322
262
  version = _object(result.stdout, "uv version query").get("version")
323
263
  if not isinstance(version, str) or not version.strip():
@@ -487,19 +427,18 @@ def prepare_update(
487
427
  if selected is None:
488
428
  raise PackageUpdateError("Installer identity is absent. Explicitly choose --via pip or --via uv-pip for a self-managed environment, or update manually.")
489
429
  _check_environment_options(selected, env)
490
- _check_tool_config(selected, prefix, env)
491
430
  if selected == "pip":
492
431
  if not info.get("pip_available"):
493
432
  raise PackageUpdateError("This environment has no pip. Netizen will not install one or choose an unrelated pip; update manually.")
494
- overrides.update({"PIP_DISABLE_PIP_VERSION_CHECK": "1", "PIP_CONFIG_FILE": os.devnull})
433
+ overrides.update({"PIP_DISABLE_PIP_VERSION_CHECK": "1"})
495
434
  command = [executable, "-I", "-m", "pip", "install", "--upgrade", "--no-input", DISTRIBUTION]
496
435
  elif selected == "uv-pip":
497
436
  assert uv is not None
498
- command = [uv, "--no-config", "--no-python-downloads", "pip", "install", "--python", executable,
437
+ command = [uv, "--no-python-downloads", "pip", "install", "--python", executable,
499
438
  "--upgrade", DISTRIBUTION]
500
439
  else:
501
440
  assert uv is not None
502
- command = [uv, "--no-config", "--no-python-downloads", "tool", "upgrade", DISTRIBUTION]
441
+ command = [uv, "--no-python-downloads", "tool", "upgrade", DISTRIBUTION]
503
442
  env.update(overrides)
504
443
  if uv is not None:
505
444
  paths[uv] = _identity(Path(uv))
@@ -598,10 +598,6 @@ class ServiceManager:
598
598
  raise ServiceError(f"service did not fully exit within {timeout:g}s; no further action performed")
599
599
  time.sleep(min(0.25, max(0.0, deadline - time.monotonic())))
600
600
 
601
- def restart(self, root: Path) -> ServiceStatus:
602
- self.stop(root)
603
- return self.start(root)
604
-
605
601
  def remove(self, root: Path) -> None:
606
602
  root = self._root(root)
607
603
  if self.inspect(root) is None: