thth 3.18.3__tar.gz → 3.19.2__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 (641) hide show
  1. {thth-3.18.3 → thth-3.19.2}/PKG-INFO +5 -2
  2. {thth-3.18.3 → thth-3.19.2}/README.md +4 -1
  3. {thth-3.18.3 → thth-3.19.2}/skills/thth/SKILL.md +8 -0
  4. {thth-3.18.3 → thth-3.19.2}/tests/test_ask.py +5 -1
  5. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_json_contract.py +3 -1
  6. thth-3.19.2/tests/test_v3192_publish_hold.py +242 -0
  7. thth-3.19.2/tests/test_x_community.py +427 -0
  8. thth-3.19.2/tests/test_x_trends_counts.py +188 -0
  9. thth-3.19.2/thth/VERSION +1 -0
  10. {thth-3.18.3 → thth-3.19.2}/thth/account_cli.py +2 -1
  11. {thth-3.18.3 → thth-3.19.2}/thth/account_settings.py +25 -7
  12. {thth-3.18.3 → thth-3.19.2}/thth/adapters/base.py +6 -0
  13. {thth-3.18.3 → thth-3.19.2}/thth/adapters/x.py +273 -0
  14. {thth-3.18.3 → thth-3.19.2}/thth/adapters/x_media.py +6 -0
  15. {thth-3.18.3 → thth-3.19.2}/thth/admin_log.py +4 -1
  16. {thth-3.18.3 → thth-3.19.2}/thth/approval.py +31 -8
  17. {thth-3.18.3 → thth-3.19.2}/thth/budget_x.py +94 -6
  18. {thth-3.18.3 → thth-3.19.2}/thth/bundle.py +4 -0
  19. {thth-3.18.3 → thth-3.19.2}/thth/cli.py +20 -0
  20. thth-3.19.2/thth/community_cli.py +143 -0
  21. {thth-3.18.3 → thth-3.19.2}/thth/core.py +64 -8
  22. {thth-3.18.3 → thth-3.19.2}/thth/fingerprint_golden.py +5 -0
  23. {thth-3.18.3 → thth-3.19.2}/thth/healthcheck.py +23 -0
  24. {thth-3.18.3 → thth-3.19.2}/thth/leave_gate.py +2 -1
  25. {thth-3.18.3 → thth-3.19.2}/thth/lint.py +32 -0
  26. {thth-3.18.3 → thth-3.19.2}/thth/morning.py +21 -0
  27. thth-3.19.2/thth/publish_hold.py +170 -0
  28. {thth-3.18.3 → thth-3.19.2}/thth/relay.py +3 -1
  29. {thth-3.18.3 → thth-3.19.2}/thth/report.py +12 -0
  30. {thth-3.18.3 → thth-3.19.2}/thth/runs.py +15 -0
  31. {thth-3.18.3 → thth-3.19.2}/thth/select.py +8 -0
  32. {thth-3.18.3 → thth-3.19.2}/thth/sent.py +9 -1
  33. {thth-3.18.3 → thth-3.19.2}/thth/server_writes.py +4 -0
  34. {thth-3.18.3 → thth-3.19.2}/thth/threadthrow.py +9 -0
  35. thth-3.19.2/thth/trends_cli.py +187 -0
  36. thth-3.18.3/thth/VERSION +0 -1
  37. {thth-3.18.3 → thth-3.19.2}/.gitignore +0 -0
  38. {thth-3.18.3 → thth-3.19.2}/LICENSE +0 -0
  39. {thth-3.18.3 → thth-3.19.2}/accounts.example/bluesky.json +0 -0
  40. {thth-3.18.3 → thth-3.19.2}/accounts.example/mastodon.json +0 -0
  41. {thth-3.18.3 → thth-3.19.2}/accounts.example/threads.json +0 -0
  42. {thth-3.18.3 → thth-3.19.2}/accounts.example/x.json +0 -0
  43. {thth-3.18.3 → thth-3.19.2}/bin/thth +0 -0
  44. {thth-3.18.3 → thth-3.19.2}/bin/thth-remote +0 -0
  45. {thth-3.18.3 → thth-3.19.2}/bin/thth-run +0 -0
  46. {thth-3.18.3 → thth-3.19.2}/mcp/server.py +0 -0
  47. {thth-3.18.3 → thth-3.19.2}/pyproject.toml +0 -0
  48. {thth-3.18.3 → thth-3.19.2}/skills/thth-admin/SKILL.md +0 -0
  49. {thth-3.18.3 → thth-3.19.2}/systemd/thth@.service +0 -0
  50. {thth-3.18.3 → thth-3.19.2}/tests/__init__.py +0 -0
  51. {thth-3.18.3 → thth-3.19.2}/tests/conftest.py +0 -0
  52. {thth-3.18.3 → thth-3.19.2}/tests/coordination_snapshot.py +0 -0
  53. {thth-3.18.3 → thth-3.19.2}/tests/fixtures/GraphemeBreakTest-17.0.0.txt +0 -0
  54. {thth-3.18.3 → thth-3.19.2}/tests/fixtures/build_injection_eval.py +0 -0
  55. {thth-3.18.3 → thth-3.19.2}/tests/fixtures/callback/worker_responses.json +0 -0
  56. {thth-3.18.3 → thth-3.19.2}/tests/fixtures/injection_eval.json +0 -0
  57. {thth-3.18.3 → thth-3.19.2}/tests/fixtures/umami-bile.md +0 -0
  58. {thth-3.18.3 → thth-3.19.2}/tests/helpers/__init__.py +0 -0
  59. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_oauth_server.py +0 -0
  60. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_push_adapter.py +0 -0
  61. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_redirect_server.py +0 -0
  62. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_search_adapter.py +0 -0
  63. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_reader.py +0 -0
  64. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_status.py +0 -0
  65. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_writes.py +0 -0
  66. {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_x.py +0 -0
  67. {thth-3.18.3 → thth-3.19.2}/tests/helpers/hold_lock.py +0 -0
  68. {thth-3.18.3 → thth-3.19.2}/tests/helpers/hold_repo_lock.py +0 -0
  69. {thth-3.18.3 → thth-3.19.2}/tests/helpers/worker_probe.mjs +0 -0
  70. {thth-3.18.3 → thth-3.19.2}/tests/test_27_acceptance_fixes.py +0 -0
  71. {thth-3.18.3 → thth-3.19.2}/tests/test_account_name_check.py +0 -0
  72. {thth-3.18.3 → thth-3.19.2}/tests/test_account_report.py +0 -0
  73. {thth-3.18.3 → thth-3.19.2}/tests/test_accounts_dir.py +0 -0
  74. {thth-3.18.3 → thth-3.19.2}/tests/test_adapter_boundary.py +0 -0
  75. {thth-3.18.3 → thth-3.19.2}/tests/test_admin_http_mcp.py +0 -0
  76. {thth-3.18.3 → thth-3.19.2}/tests/test_admin_log.py +0 -0
  77. {thth-3.18.3 → thth-3.19.2}/tests/test_admin_notifications.py +0 -0
  78. {thth-3.18.3 → thth-3.19.2}/tests/test_admin_repairs.py +0 -0
  79. {thth-3.18.3 → thth-3.19.2}/tests/test_admin_report.py +0 -0
  80. {thth-3.18.3 → thth-3.19.2}/tests/test_after_cli.py +0 -0
  81. {thth-3.18.3 → thth-3.19.2}/tests/test_analytics_comparison.py +0 -0
  82. {thth-3.18.3 → thth-3.19.2}/tests/test_analytics_report.py +0 -0
  83. {thth-3.18.3 → thth-3.19.2}/tests/test_api_diagnostic.py +0 -0
  84. {thth-3.18.3 → thth-3.19.2}/tests/test_api_error_body.py +0 -0
  85. {thth-3.18.3 → thth-3.19.2}/tests/test_app_env_cli.py +0 -0
  86. {thth-3.18.3 → thth-3.19.2}/tests/test_approval.py +0 -0
  87. {thth-3.18.3 → thth-3.19.2}/tests/test_approve_cmd.py +0 -0
  88. {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_fifth_review.py +0 -0
  89. {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_fourth_review.py +0 -0
  90. {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_review.py +0 -0
  91. {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_second_review.py +0 -0
  92. {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_third_review.py +0 -0
  93. {thth-3.18.3 → thth-3.19.2}/tests/test_audit1_fixes.py +0 -0
  94. {thth-3.18.3 → thth-3.19.2}/tests/test_audit2_fixes.py +0 -0
  95. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_counterexamples.py +0 -0
  96. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_m1_semantics.py +0 -0
  97. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_n1_depth.py +0 -0
  98. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_r1_closure.py +0 -0
  99. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_v201.py +0 -0
  100. {thth-3.18.3 → thth-3.19.2}/tests/test_audit_v23_details.py +0 -0
  101. {thth-3.18.3 → thth-3.19.2}/tests/test_auth.py +0 -0
  102. {thth-3.18.3 → thth-3.19.2}/tests/test_auth_identity_required.py +0 -0
  103. {thth-3.18.3 → thth-3.19.2}/tests/test_behind_remote.py +0 -0
  104. {thth-3.18.3 → thth-3.19.2}/tests/test_bluesky_adapter.py +0 -0
  105. {thth-3.18.3 → thth-3.19.2}/tests/test_bluesky_secret_scrub.py +0 -0
  106. {thth-3.18.3 → thth-3.19.2}/tests/test_board_needs_review.py +0 -0
  107. {thth-3.18.3 → thth-3.19.2}/tests/test_board_running.py +0 -0
  108. {thth-3.18.3 → thth-3.19.2}/tests/test_branch_replies.py +0 -0
  109. {thth-3.18.3 → thth-3.19.2}/tests/test_bundle.py +0 -0
  110. {thth-3.18.3 → thth-3.19.2}/tests/test_bundle_not_type_mismatch.py +0 -0
  111. {thth-3.18.3 → thth-3.19.2}/tests/test_charcount.py +0 -0
  112. {thth-3.18.3 → thth-3.19.2}/tests/test_cli_entrypoint.py +0 -0
  113. {thth-3.18.3 → thth-3.19.2}/tests/test_cli_help.py +0 -0
  114. {thth-3.18.3 → thth-3.19.2}/tests/test_cli_vm_path.py +0 -0
  115. {thth-3.18.3 → thth-3.19.2}/tests/test_collect.py +0 -0
  116. {thth-3.18.3 → thth-3.19.2}/tests/test_collect_engagements.py +0 -0
  117. {thth-3.18.3 → thth-3.19.2}/tests/test_collect_runs.py +0 -0
  118. {thth-3.18.3 → thth-3.19.2}/tests/test_collect_sent.py +0 -0
  119. {thth-3.18.3 → thth-3.19.2}/tests/test_comparability.py +0 -0
  120. {thth-3.18.3 → thth-3.19.2}/tests/test_control_chars_refused.py +0 -0
  121. {thth-3.18.3 → thth-3.19.2}/tests/test_conversation_paging.py +0 -0
  122. {thth-3.18.3 → thth-3.19.2}/tests/test_count_for.py +0 -0
  123. {thth-3.18.3 → thth-3.19.2}/tests/test_docs_links.py +0 -0
  124. {thth-3.18.3 → thth-3.19.2}/tests/test_doctor.py +0 -0
  125. {thth-3.18.3 → thth-3.19.2}/tests/test_doctor_all_permissions.py +0 -0
  126. {thth-3.18.3 → thth-3.19.2}/tests/test_doctor_next_step.py +0 -0
  127. {thth-3.18.3 → thth-3.19.2}/tests/test_duplicate_front_matter_keys.py +0 -0
  128. {thth-3.18.3 → thth-3.19.2}/tests/test_editorial_audit.py +0 -0
  129. {thth-3.18.3 → thth-3.19.2}/tests/test_editorial_n3_n4.py +0 -0
  130. {thth-3.18.3 → thth-3.19.2}/tests/test_engagements.py +0 -0
  131. {thth-3.18.3 → thth-3.19.2}/tests/test_external_acceptance.py +0 -0
  132. {thth-3.18.3 → thth-3.19.2}/tests/test_fake_api.py +0 -0
  133. {thth-3.18.3 → thth-3.19.2}/tests/test_form_spec.py +0 -0
  134. {thth-3.18.3 → thth-3.19.2}/tests/test_form_spec_cli.py +0 -0
  135. {thth-3.18.3 → thth-3.19.2}/tests/test_forms.py +0 -0
  136. {thth-3.18.3 → thth-3.19.2}/tests/test_fresh_install.py +0 -0
  137. {thth-3.18.3 → thth-3.19.2}/tests/test_front_matter_injection.py +0 -0
  138. {thth-3.18.3 → thth-3.19.2}/tests/test_healthcheck_notifications.py +0 -0
  139. {thth-3.18.3 → thth-3.19.2}/tests/test_hypotheses.py +0 -0
  140. {thth-3.18.3 → thth-3.19.2}/tests/test_hypothesis_boundaries.py +0 -0
  141. {thth-3.18.3 → thth-3.19.2}/tests/test_hypothesis_units.py +0 -0
  142. {thth-3.18.3 → thth-3.19.2}/tests/test_impact_cli.py +0 -0
  143. {thth-3.18.3 → thth-3.19.2}/tests/test_inbox_granted_scopes.py +0 -0
  144. {thth-3.18.3 → thth-3.19.2}/tests/test_incident_notifications.py +0 -0
  145. {thth-3.18.3 → thth-3.19.2}/tests/test_independent_thread_review.py +0 -0
  146. {thth-3.18.3 → thth-3.19.2}/tests/test_independent_topic_review.py +0 -0
  147. {thth-3.18.3 → thth-3.19.2}/tests/test_independent_topic_review_r2.py +0 -0
  148. {thth-3.18.3 → thth-3.19.2}/tests/test_inflight.py +0 -0
  149. {thth-3.18.3 → thth-3.19.2}/tests/test_inflight_tag_body_hash.py +0 -0
  150. {thth-3.18.3 → thth-3.19.2}/tests/test_jst.py +0 -0
  151. {thth-3.18.3 → thth-3.19.2}/tests/test_lint.py +0 -0
  152. {thth-3.18.3 → thth-3.19.2}/tests/test_list_projections.py +0 -0
  153. {thth-3.18.3 → thth-3.19.2}/tests/test_llm_trial.py +0 -0
  154. {thth-3.18.3 → thth-3.19.2}/tests/test_llm_trial_engage.py +0 -0
  155. {thth-3.18.3 → thth-3.19.2}/tests/test_lock.py +0 -0
  156. {thth-3.18.3 → thth-3.19.2}/tests/test_m2_independent.py +0 -0
  157. {thth-3.18.3 → thth-3.19.2}/tests/test_maintain.py +0 -0
  158. {thth-3.18.3 → thth-3.19.2}/tests/test_mastodon_adapter.py +0 -0
  159. {thth-3.18.3 → thth-3.19.2}/tests/test_mastodon_visibility.py +0 -0
  160. {thth-3.18.3 → thth-3.19.2}/tests/test_max_per_run.py +0 -0
  161. {thth-3.18.3 → thth-3.19.2}/tests/test_mcp.py +0 -0
  162. {thth-3.18.3 → thth-3.19.2}/tests/test_mcp_robustness.py +0 -0
  163. {thth-3.18.3 → thth-3.19.2}/tests/test_measured.py +0 -0
  164. {thth-3.18.3 → thth-3.19.2}/tests/test_media_accounts.py +0 -0
  165. {thth-3.18.3 → thth-3.19.2}/tests/test_media_next_steps.py +0 -0
  166. {thth-3.18.3 → thth-3.19.2}/tests/test_media_roundtrip.py +0 -0
  167. {thth-3.18.3 → thth-3.19.2}/tests/test_mismatch_diagnostics.py +0 -0
  168. {thth-3.18.3 → thth-3.19.2}/tests/test_n5_reply_null_element.py +0 -0
  169. {thth-3.18.3 → thth-3.19.2}/tests/test_n6_replies_incomplete_ledger.py +0 -0
  170. {thth-3.18.3 → thth-3.19.2}/tests/test_n7_doctor_error_body.py +0 -0
  171. {thth-3.18.3 → thth-3.19.2}/tests/test_no_limits.py +0 -0
  172. {thth-3.18.3 → thth-3.19.2}/tests/test_observation_provenance.py +0 -0
  173. {thth-3.18.3 → thth-3.19.2}/tests/test_operations_handoff.py +0 -0
  174. {thth-3.18.3 → thth-3.19.2}/tests/test_packaging.py +0 -0
  175. {thth-3.18.3 → thth-3.19.2}/tests/test_preview.py +0 -0
  176. {thth-3.18.3 → thth-3.19.2}/tests/test_production_mode.py +0 -0
  177. {thth-3.18.3 → thth-3.19.2}/tests/test_pull_cli.py +0 -0
  178. {thth-3.18.3 → thth-3.19.2}/tests/test_pulse.py +0 -0
  179. {thth-3.18.3 → thth-3.19.2}/tests/test_queue.py +0 -0
  180. {thth-3.18.3 → thth-3.19.2}/tests/test_quiet_hours.py +0 -0
  181. {thth-3.18.3 → thth-3.19.2}/tests/test_r2_r4_r5.py +0 -0
  182. {thth-3.18.3 → thth-3.19.2}/tests/test_read_cli_bare_runtimeerror.py +0 -0
  183. {thth-3.18.3 → thth-3.19.2}/tests/test_reason_adoption.py +0 -0
  184. {thth-3.18.3 → thth-3.19.2}/tests/test_redact.py +0 -0
  185. {thth-3.18.3 → thth-3.19.2}/tests/test_redirect_token_leak.py +0 -0
  186. {thth-3.18.3 → thth-3.19.2}/tests/test_refresh.py +0 -0
  187. {thth-3.18.3 → thth-3.19.2}/tests/test_refresh_destination.py +0 -0
  188. {thth-3.18.3 → thth-3.19.2}/tests/test_rejudge_new.py +0 -0
  189. {thth-3.18.3 → thth-3.19.2}/tests/test_rejudge_r2_r3.py +0 -0
  190. {thth-3.18.3 → thth-3.19.2}/tests/test_replies.py +0 -0
  191. {thth-3.18.3 → thth-3.19.2}/tests/test_replies_refresh.py +0 -0
  192. {thth-3.18.3 → thth-3.19.2}/tests/test_repo_lock.py +0 -0
  193. {thth-3.18.3 → thth-3.19.2}/tests/test_repo_sync.py +0 -0
  194. {thth-3.18.3 → thth-3.19.2}/tests/test_report_checkout_import.py +0 -0
  195. {thth-3.18.3 → thth-3.19.2}/tests/test_report_http.py +0 -0
  196. {thth-3.18.3 → thth-3.19.2}/tests/test_report_isolation.py +0 -0
  197. {thth-3.18.3 → thth-3.19.2}/tests/test_report_service.py +0 -0
  198. {thth-3.18.3 → thth-3.19.2}/tests/test_retract_already_gone.py +0 -0
  199. {thth-3.18.3 → thth-3.19.2}/tests/test_reverse_audit.py +0 -0
  200. {thth-3.18.3 → thth-3.19.2}/tests/test_review_case_id_cluster_m2.py +0 -0
  201. {thth-3.18.3 → thth-3.19.2}/tests/test_review_case_id_cluster_r2.py +0 -0
  202. {thth-3.18.3 → thth-3.19.2}/tests/test_review_cli.py +0 -0
  203. {thth-3.18.3 → thth-3.19.2}/tests/test_review_evidence_account.py +0 -0
  204. {thth-3.18.3 → thth-3.19.2}/tests/test_review_form_spec_and_case_id.py +0 -0
  205. {thth-3.18.3 → thth-3.19.2}/tests/test_review_provenance.py +0 -0
  206. {thth-3.18.3 → thth-3.19.2}/tests/test_review_records.py +0 -0
  207. {thth-3.18.3 → thth-3.19.2}/tests/test_revoke.py +0 -0
  208. {thth-3.18.3 → thth-3.19.2}/tests/test_roundtrip.py +0 -0
  209. {thth-3.18.3 → thth-3.19.2}/tests/test_run_missing_env.py +0 -0
  210. {thth-3.18.3 → thth-3.19.2}/tests/test_run_record_failclosed.py +0 -0
  211. {thth-3.18.3 → thth-3.19.2}/tests/test_runs_collected.py +0 -0
  212. {thth-3.18.3 → thth-3.19.2}/tests/test_runs_read_rows.py +0 -0
  213. {thth-3.18.3 → thth-3.19.2}/tests/test_schedule_multiple.py +0 -0
  214. {thth-3.18.3 → thth-3.19.2}/tests/test_schedule_view.py +0 -0
  215. {thth-3.18.3 → thth-3.19.2}/tests/test_scopes_source_requested.py +0 -0
  216. {thth-3.18.3 → thth-3.19.2}/tests/test_search_engage_targets.py +0 -0
  217. {thth-3.18.3 → thth-3.19.2}/tests/test_search_media_routes.py +0 -0
  218. {thth-3.18.3 → thth-3.19.2}/tests/test_secret_value_redact.py +0 -0
  219. {thth-3.18.3 → thth-3.19.2}/tests/test_secrets_grep.py +0 -0
  220. {thth-3.18.3 → thth-3.19.2}/tests/test_security_small_fixes.py +0 -0
  221. {thth-3.18.3 → thth-3.19.2}/tests/test_select.py +0 -0
  222. {thth-3.18.3 → thth-3.19.2}/tests/test_selfupdate.py +0 -0
  223. {thth-3.18.3 → thth-3.19.2}/tests/test_send.py +0 -0
  224. {thth-3.18.3 → thth-3.19.2}/tests/test_send_cli.py +0 -0
  225. {thth-3.18.3 → thth-3.19.2}/tests/test_send_control_chars.py +0 -0
  226. {thth-3.18.3 → thth-3.19.2}/tests/test_send_media.py +0 -0
  227. {thth-3.18.3 → thth-3.19.2}/tests/test_send_visibility.py +0 -0
  228. {thth-3.18.3 → thth-3.19.2}/tests/test_sent_integrity.py +0 -0
  229. {thth-3.18.3 → thth-3.19.2}/tests/test_server_json.py +0 -0
  230. {thth-3.18.3 → thth-3.19.2}/tests/test_site.py +0 -0
  231. {thth-3.18.3 → thth-3.19.2}/tests/test_skill_doc.py +0 -0
  232. {thth-3.18.3 → thth-3.19.2}/tests/test_study_report.py +0 -0
  233. {thth-3.18.3 → thth-3.19.2}/tests/test_systemd.py +0 -0
  234. {thth-3.18.3 → thth-3.19.2}/tests/test_thread_publish.py +0 -0
  235. {thth-3.18.3 → thth-3.19.2}/tests/test_thread_read.py +0 -0
  236. {thth-3.18.3 → thth-3.19.2}/tests/test_threadrun.py +0 -0
  237. {thth-3.18.3 → thth-3.19.2}/tests/test_threads_read_permissions.py +0 -0
  238. {thth-3.18.3 → thth-3.19.2}/tests/test_threadshape.py +0 -0
  239. {thth-3.18.3 → thth-3.19.2}/tests/test_thth_root.py +0 -0
  240. {thth-3.18.3 → thth-3.19.2}/tests/test_token_exists.py +0 -0
  241. {thth-3.18.3 → thth-3.19.2}/tests/test_token_scopes_record.py +0 -0
  242. {thth-3.18.3 → thth-3.19.2}/tests/test_token_set.py +0 -0
  243. {thth-3.18.3 → thth-3.19.2}/tests/test_topic.py +0 -0
  244. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_advice.py +0 -0
  245. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_cli.py +0 -0
  246. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_models.py +0 -0
  247. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_review_fixes.py +0 -0
  248. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_shelf_observers.py +0 -0
  249. {thth-3.18.3 → thth-3.19.2}/tests/test_topic_store.py +0 -0
  250. {thth-3.18.3 → thth-3.19.2}/tests/test_topics_record_concurrent.py +0 -0
  251. {thth-3.18.3 → thth-3.19.2}/tests/test_topics_tool.py +0 -0
  252. {thth-3.18.3 → thth-3.19.2}/tests/test_trial_frictions.py +0 -0
  253. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_admin_transaction.py +0 -0
  254. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_approve_account.py +0 -0
  255. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_length.py +0 -0
  256. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_lock_wait.py +0 -0
  257. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_mastodon_scopes.py +0 -0
  258. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_mentions.py +0 -0
  259. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_post_urls.py +0 -0
  260. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_repo_paths.py +0 -0
  261. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_reposts.py +0 -0
  262. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_study_add.py +0 -0
  263. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_tool_version.py +0 -0
  264. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_unanswered.py +0 -0
  265. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_unanswered_scope.py +0 -0
  266. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_where_arguments.py +0 -0
  267. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_where_filters.py +0 -0
  268. {thth-3.18.3 → thth-3.19.2}/tests/test_v210_who_arguments.py +0 -0
  269. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_auth_integration.py +0 -0
  270. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_authflow.py +0 -0
  271. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_bluesky_stdin.py +0 -0
  272. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_doctor_binding.py +0 -0
  273. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_mastodon_auth.py +0 -0
  274. {thth-3.18.3 → thth-3.19.2}/tests/test_v211_x_auth.py +0 -0
  275. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_ask_coordination.py +0 -0
  276. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget.py +0 -0
  277. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget_auth.py +0 -0
  278. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget_mcp.py +0 -0
  279. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_deletion.py +0 -0
  280. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave.py +0 -0
  281. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_gate.py +0 -0
  282. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_providers.py +0 -0
  283. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_token_safety.py +0 -0
  284. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_mastodon_guide.py +0 -0
  285. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_mcp_compat.py +0 -0
  286. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_missing_token.py +0 -0
  287. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_read_coordination.py +0 -0
  288. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_relay.py +0 -0
  289. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_server_writes.py +0 -0
  290. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_token_parent.py +0 -0
  291. {thth-3.18.3 → thth-3.19.2}/tests/test_v212_write_storage.py +0 -0
  292. {thth-3.18.3 → thth-3.19.2}/tests/test_v2131_send_dry_run.py +0 -0
  293. {thth-3.18.3 → thth-3.19.2}/tests/test_v2131_threads_publish_wait.py +0 -0
  294. {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_send_inflight_hint.py +0 -0
  295. {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_threads_create_timeout.py +0 -0
  296. {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_threads_create_unknown.py +0 -0
  297. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_acceptance_fixes.py +0 -0
  298. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_adts_asf.py +0 -0
  299. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_attachment_kinds.py +0 -0
  300. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_external.py +0 -0
  301. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_media.py +0 -0
  302. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata.py +0 -0
  303. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata_uri.py +0 -0
  304. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata_video.py +0 -0
  305. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_record.py +0 -0
  306. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_record_video.py +0 -0
  307. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_video.py +0 -0
  308. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_webm_named.py +0 -0
  309. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bmff_typed_metadata.py +0 -0
  310. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_budget_lock.py +0 -0
  311. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_capabilities.py +0 -0
  312. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_carryover_timeout.py +0 -0
  313. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_graphemes.py +0 -0
  314. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_auth_media.py +0 -0
  315. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_bmff_audio.py +0 -0
  316. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_flac.py +0 -0
  317. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_gif.py +0 -0
  318. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_link.py +0 -0
  319. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_media.py +0 -0
  320. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_mp3.py +0 -0
  321. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_ogg_opus.py +0 -0
  322. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_ogg_vorbis.py +0 -0
  323. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_poll.py +0 -0
  324. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_primary_size_boundary.py +0 -0
  325. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_quote.py +0 -0
  326. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_thumbnail.py +0 -0
  327. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_wav.py +0 -0
  328. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_webm_audio.py +0 -0
  329. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_webm_video.py +0 -0
  330. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_cleanup.py +0 -0
  331. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_formats.py +0 -0
  332. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_foundation.py +0 -0
  333. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_prepared.py +0 -0
  334. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_relay.py +0 -0
  335. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_relay_refusals.py +0 -0
  336. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_upload.py +0 -0
  337. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_review_followups.py +0 -0
  338. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_stage810_audit.py +0 -0
  339. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_static_diagnostics.py +0 -0
  340. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_stop_observation.py +0 -0
  341. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_systemd_worker.py +0 -0
  342. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_ghost.py +0 -0
  343. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_gif.py +0 -0
  344. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_link.py +0 -0
  345. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_media.py +0 -0
  346. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_media_spoiler.py +0 -0
  347. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_poll.py +0 -0
  348. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_quote.py +0 -0
  349. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_quote_media.py +0 -0
  350. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_replies.py +0 -0
  351. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_text.py +0 -0
  352. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_text_spoiler.py +0 -0
  353. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_video.py +0 -0
  354. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_transport_review.py +0 -0
  355. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_video_typed_metadata.py +0 -0
  356. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_vorbis_comment_boundary.py +0 -0
  357. {thth-3.18.3 → thth-3.19.2}/tests/test_v213_webm_schema_boundary.py +0 -0
  358. {thth-3.18.3 → thth-3.19.2}/tests/test_v2141_draft_lint_reason.py +0 -0
  359. {thth-3.18.3 → thth-3.19.2}/tests/test_v2141_managed_repo_umask.py +0 -0
  360. {thth-3.18.3 → thth-3.19.2}/tests/test_v214_release_signing.py +0 -0
  361. {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_adapter.py +0 -0
  362. {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_auth.py +0 -0
  363. {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_media.py +0 -0
  364. {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_posts_budget.py +0 -0
  365. {thth-3.18.3 → thth-3.19.2}/tests/test_v21b_approved_writes.py +0 -0
  366. {thth-3.18.3 → thth-3.19.2}/tests/test_v28_tags.py +0 -0
  367. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_docs.py +0 -0
  368. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_admin_approval.py +0 -0
  369. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_create.py +0 -0
  370. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_credential.py +0 -0
  371. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_limits.py +0 -0
  372. {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_worker.py +0 -0
  373. {thth-3.18.3 → thth-3.19.2}/tests/test_v310_morning.py +0 -0
  374. {thth-3.18.3 → thth-3.19.2}/tests/test_v310_search_timeout.py +0 -0
  375. {thth-3.18.3 → thth-3.19.2}/tests/test_v310_watch_words.py +0 -0
  376. {thth-3.18.3 → thth-3.19.2}/tests/test_v3111_observe_counts_only.py +0 -0
  377. {thth-3.18.3 → thth-3.19.2}/tests/test_v3111_observe_no_world.py +0 -0
  378. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_leave_same_user.py +0 -0
  379. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_mastodon_retract.py +0 -0
  380. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_overdue.py +0 -0
  381. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_own_exclusion.py +0 -0
  382. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_unanswered_window.py +0 -0
  383. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_notifications_guidance.py +0 -0
  384. {thth-3.18.3 → thth-3.19.2}/tests/test_v311_replies_owned.py +0 -0
  385. {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_activity.py +0 -0
  386. {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_admin_write_reasons.py +0 -0
  387. {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_guard.py +0 -0
  388. {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_worker_version.py +0 -0
  389. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_leave_shared_token.py +0 -0
  390. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_own_handles_stopped.py +0 -0
  391. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_admin.py +0 -0
  392. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_channel.py +0 -0
  393. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_inbox.py +0 -0
  394. {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_mcp_user.py +0 -0
  395. {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_api_relay.py +0 -0
  396. {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_invite_key.py +0 -0
  397. {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_remote_cli.py +0 -0
  398. {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_server_reads.py +0 -0
  399. {thth-3.18.3 → thth-3.19.2}/tests/test_v3142_browser_login.py +0 -0
  400. {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_activity_push.py +0 -0
  401. {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_cli_umask_leave.py +0 -0
  402. {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_inflight_remote.py +0 -0
  403. {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_managed_repo_recover.py +0 -0
  404. {thth-3.18.3 → thth-3.19.2}/tests/test_v315_reactions.py +0 -0
  405. {thth-3.18.3 → thth-3.19.2}/tests/test_v317_run_lock_wait.py +0 -0
  406. {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_json_names.py +0 -0
  407. {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_map_timer.py +0 -0
  408. {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_where_filters.py +0 -0
  409. {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_where_keep.py +0 -0
  410. {thth-3.18.3 → thth-3.19.2}/tests/test_v31_analysis.py +0 -0
  411. {thth-3.18.3 → thth-3.19.2}/tests/test_v31_collection.py +0 -0
  412. {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_display.py +0 -0
  413. {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_lint.py +0 -0
  414. {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_resolve.py +0 -0
  415. {thth-3.18.3 → thth-3.19.2}/tests/test_v320_report_fixes.py +0 -0
  416. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_fingerprint_version.py +0 -0
  417. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_held.py +0 -0
  418. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_held_names.py +0 -0
  419. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_last_refusals.py +0 -0
  420. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_notification_route.py +0 -0
  421. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_observe.py +0 -0
  422. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_report_friction.py +0 -0
  423. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_report_words.py +0 -0
  424. {thth-3.18.3 → thth-3.19.2}/tests/test_v330_reports_effect.py +0 -0
  425. {thth-3.18.3 → thth-3.19.2}/tests/test_v331_inflight_cli.py +0 -0
  426. {thth-3.18.3 → thth-3.19.2}/tests/test_v331_listing_resolve.py +0 -0
  427. {thth-3.18.3 → thth-3.19.2}/tests/test_v331_outbox_retention.py +0 -0
  428. {thth-3.18.3 → thth-3.19.2}/tests/test_v331_publish_status.py +0 -0
  429. {thth-3.18.3 → thth-3.19.2}/tests/test_v331_self_resolve.py +0 -0
  430. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_cli.py +0 -0
  431. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_docs.py +0 -0
  432. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_fields.py +0 -0
  433. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_mcp.py +0 -0
  434. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_morning.py +0 -0
  435. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_observe.py +0 -0
  436. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_open.py +0 -0
  437. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_open_confirm.py +0 -0
  438. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_reply.py +0 -0
  439. {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_store.py +0 -0
  440. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_docs.py +0 -0
  441. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_nodes.py +0 -0
  442. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_observe.py +0 -0
  443. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_plaza.py +0 -0
  444. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_retention.py +0 -0
  445. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_self.py +0 -0
  446. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_show.py +0 -0
  447. {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_world.py +0 -0
  448. {thth-3.18.3 → thth-3.19.2}/tests/test_v351_leave_timers.py +0 -0
  449. {thth-3.18.3 → thth-3.19.2}/tests/test_v351_plaza_open_holes.py +0 -0
  450. {thth-3.18.3 → thth-3.19.2}/tests/test_v351_who_owned.py +0 -0
  451. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_analytics.py +0 -0
  452. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_docs.py +0 -0
  453. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_observe_map.py +0 -0
  454. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_plaza.py +0 -0
  455. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_record.py +0 -0
  456. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_send.py +0 -0
  457. {thth-3.18.3 → thth-3.19.2}/tests/test_v360_report_timeline.py +0 -0
  458. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_account_self_healing.py +0 -0
  459. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_approve_pending.py +0 -0
  460. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_click_attribution.py +0 -0
  461. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_collection_stale_basis.py +0 -0
  462. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_docs.py +0 -0
  463. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_follow_comparison.py +0 -0
  464. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_local_path.py +0 -0
  465. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_weekly_goals.py +0 -0
  466. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_aggregate.py +0 -0
  467. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_also.py +0 -0
  468. {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_zero.py +0 -0
  469. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_docs.py +0 -0
  470. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_digest.py +0 -0
  471. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_from.py +0 -0
  472. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_mcp.py +0 -0
  473. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_moments.py +0 -0
  474. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_owner.py +0 -0
  475. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_received.py +0 -0
  476. {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_triggers.py +0 -0
  477. {thth-3.18.3 → thth-3.19.2}/tests/test_v381_plaza_visibility_default.py +0 -0
  478. {thth-3.18.3 → thth-3.19.2}/tests/test_v382_confirm_file.py +0 -0
  479. {thth-3.18.3 → thth-3.19.2}/tests/test_v382_first_stage_not_refusal.py +0 -0
  480. {thth-3.18.3 → thth-3.19.2}/tests/test_v382_reader_lock_and_push_pending.py +0 -0
  481. {thth-3.18.3 → thth-3.19.2}/tests/test_v382_sync_without_fetch_head.py +0 -0
  482. {thth-3.18.3 → thth-3.19.2}/tests/test_v390_docs.py +0 -0
  483. {thth-3.18.3 → thth-3.19.2}/tests/test_v390_per_post_clicks.py +0 -0
  484. {thth-3.18.3 → thth-3.19.2}/tests/test_v390_where_rate.py +0 -0
  485. {thth-3.18.3 → thth-3.19.2}/tests/test_v390_where_suggest.py +0 -0
  486. {thth-3.18.3 → thth-3.19.2}/tests/test_v391_plaza_text_numbers.py +0 -0
  487. {thth-3.18.3 → thth-3.19.2}/tests/test_value_domains_shown.py +0 -0
  488. {thth-3.18.3 → thth-3.19.2}/tests/test_version.py +0 -0
  489. {thth-3.18.3 → thth-3.19.2}/tests/test_where_cli.py +0 -0
  490. {thth-3.18.3 → thth-3.19.2}/tests/test_where_threads_tag_author.py +0 -0
  491. {thth-3.18.3 → thth-3.19.2}/tests/test_who_cli.py +0 -0
  492. {thth-3.18.3 → thth-3.19.2}/tests/test_writeback_rebase.py +0 -0
  493. {thth-3.18.3 → thth-3.19.2}/tests/test_writeback_validate.py +0 -0
  494. {thth-3.18.3 → thth-3.19.2}/tests/test_x_list.py +0 -0
  495. {thth-3.18.3 → thth-3.19.2}/tests/test_x_metrics.py +0 -0
  496. {thth-3.18.3 → thth-3.19.2}/tests/test_x_owned_metrics.py +0 -0
  497. {thth-3.18.3 → thth-3.19.2}/tests/test_x_search_thread.py +0 -0
  498. {thth-3.18.3 → thth-3.19.2}/tests/test_x_token_autorefresh.py +0 -0
  499. {thth-3.18.3 → thth-3.19.2}/thth/__init__.py +0 -0
  500. {thth-3.18.3 → thth-3.19.2}/thth/__main__.py +0 -0
  501. {thth-3.18.3 → thth-3.19.2}/thth/_grapheme_data.py +0 -0
  502. {thth-3.18.3 → thth-3.19.2}/thth/account_report.py +0 -0
  503. {thth-3.18.3 → thth-3.19.2}/thth/accounts.py +0 -0
  504. {thth-3.18.3 → thth-3.19.2}/thth/activity.py +0 -0
  505. {thth-3.18.3 → thth-3.19.2}/thth/adapters/__init__.py +0 -0
  506. {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_mastodon.py +0 -0
  507. {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_threads.py +0 -0
  508. {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_x.py +0 -0
  509. {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky.py +0 -0
  510. {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky_media.py +0 -0
  511. {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky_video.py +0 -0
  512. {thth-3.18.3 → thth-3.19.2}/thth/adapters/mastodon.py +0 -0
  513. {thth-3.18.3 → thth-3.19.2}/thth/adapters/mastodon_media.py +0 -0
  514. {thth-3.18.3 → thth-3.19.2}/thth/adapters/threads.py +0 -0
  515. {thth-3.18.3 → thth-3.19.2}/thth/adapters/threads_media.py +0 -0
  516. {thth-3.18.3 → thth-3.19.2}/thth/admin_diagnose.py +0 -0
  517. {thth-3.18.3 → thth-3.19.2}/thth/admin_notifications.py +0 -0
  518. {thth-3.18.3 → thth-3.19.2}/thth/admin_report.py +0 -0
  519. {thth-3.18.3 → thth-3.19.2}/thth/after_cli.py +0 -0
  520. {thth-3.18.3 → thth-3.19.2}/thth/analytics_clicks.py +0 -0
  521. {thth-3.18.3 → thth-3.19.2}/thth/analytics_comparison.py +0 -0
  522. {thth-3.18.3 → thth-3.19.2}/thth/analytics_goals.py +0 -0
  523. {thth-3.18.3 → thth-3.19.2}/thth/analytics_report.py +0 -0
  524. {thth-3.18.3 → thth-3.19.2}/thth/analytics_shapes.py +0 -0
  525. {thth-3.18.3 → thth-3.19.2}/thth/analytics_threads.py +0 -0
  526. {thth-3.18.3 → thth-3.19.2}/thth/analytics_weekly.py +0 -0
  527. {thth-3.18.3 → thth-3.19.2}/thth/api_diagnostic.py +0 -0
  528. {thth-3.18.3 → thth-3.19.2}/thth/api_requests.py +0 -0
  529. {thth-3.18.3 → thth-3.19.2}/thth/appconfig.py +0 -0
  530. {thth-3.18.3 → thth-3.19.2}/thth/appenv.py +0 -0
  531. {thth-3.18.3 → thth-3.19.2}/thth/approve_pending.py +0 -0
  532. {thth-3.18.3 → thth-3.19.2}/thth/ask.py +0 -0
  533. {thth-3.18.3 → thth-3.19.2}/thth/ask_cli.py +0 -0
  534. {thth-3.18.3 → thth-3.19.2}/thth/audioformats.py +0 -0
  535. {thth-3.18.3 → thth-3.19.2}/thth/authclients.py +0 -0
  536. {thth-3.18.3 → thth-3.19.2}/thth/authflow.py +0 -0
  537. {thth-3.18.3 → thth-3.19.2}/thth/authpassword.py +0 -0
  538. {thth-3.18.3 → thth-3.19.2}/thth/bluesky_metadata.py +0 -0
  539. {thth-3.18.3 → thth-3.19.2}/thth/budget_x_posts.py +0 -0
  540. {thth-3.18.3 → thth-3.19.2}/thth/click_attribution.py +0 -0
  541. {thth-3.18.3 → thth-3.19.2}/thth/collect.py +0 -0
  542. {thth-3.18.3 → thth-3.19.2}/thth/collection_context.py +0 -0
  543. {thth-3.18.3 → thth-3.19.2}/thth/collection_status.py +0 -0
  544. {thth-3.18.3 → thth-3.19.2}/thth/deletion.py +0 -0
  545. {thth-3.18.3 → thth-3.19.2}/thth/doctor.py +0 -0
  546. {thth-3.18.3 → thth-3.19.2}/thth/ebmlaudio.py +0 -0
  547. {thth-3.18.3 → thth-3.19.2}/thth/ebmlvideo.py +0 -0
  548. {thth-3.18.3 → thth-3.19.2}/thth/engagements.py +0 -0
  549. {thth-3.18.3 → thth-3.19.2}/thth/flacformats.py +0 -0
  550. {thth-3.18.3 → thth-3.19.2}/thth/forms.py +0 -0
  551. {thth-3.18.3 → thth-3.19.2}/thth/goals.py +0 -0
  552. {thth-3.18.3 → thth-3.19.2}/thth/graphemes.py +0 -0
  553. {thth-3.18.3 → thth-3.19.2}/thth/guard.py +0 -0
  554. {thth-3.18.3 → thth-3.19.2}/thth/handoff_cursor.py +0 -0
  555. {thth-3.18.3 → thth-3.19.2}/thth/httpsafe.py +0 -0
  556. {thth-3.18.3 → thth-3.19.2}/thth/incident.py +0 -0
  557. {thth-3.18.3 → thth-3.19.2}/thth/inflight.py +0 -0
  558. {thth-3.18.3 → thth-3.19.2}/thth/inflight_cli.py +0 -0
  559. {thth-3.18.3 → thth-3.19.2}/thth/inflight_resolve.py +0 -0
  560. {thth-3.18.3 → thth-3.19.2}/thth/invites.py +0 -0
  561. {thth-3.18.3 → thth-3.19.2}/thth/jst.py +0 -0
  562. {thth-3.18.3 → thth-3.19.2}/thth/leave.py +0 -0
  563. {thth-3.18.3 → thth-3.19.2}/thth/list_cli.py +0 -0
  564. {thth-3.18.3 → thth-3.19.2}/thth/lock.py +0 -0
  565. {thth-3.18.3 → thth-3.19.2}/thth/maintain.py +0 -0
  566. {thth-3.18.3 → thth-3.19.2}/thth/managed_repo.py +0 -0
  567. {thth-3.18.3 → thth-3.19.2}/thth/map_cli.py +0 -0
  568. {thth-3.18.3 → thth-3.19.2}/thth/map_store.py +0 -0
  569. {thth-3.18.3 → thth-3.19.2}/thth/map_view.py +0 -0
  570. {thth-3.18.3 → thth-3.19.2}/thth/map_world.py +0 -0
  571. {thth-3.18.3 → thth-3.19.2}/thth/measured.py +0 -0
  572. {thth-3.18.3 → thth-3.19.2}/thth/media.py +0 -0
  573. {thth-3.18.3 → thth-3.19.2}/thth/media_capabilities.py +0 -0
  574. {thth-3.18.3 → thth-3.19.2}/thth/media_cleanup.py +0 -0
  575. {thth-3.18.3 → thth-3.19.2}/thth/media_delivery.py +0 -0
  576. {thth-3.18.3 → thth-3.19.2}/thth/media_relay.py +0 -0
  577. {thth-3.18.3 → thth-3.19.2}/thth/media_uploads.py +0 -0
  578. {thth-3.18.3 → thth-3.19.2}/thth/mediaformats.py +0 -0
  579. {thth-3.18.3 → thth-3.19.2}/thth/mpeg_audio.py +0 -0
  580. {thth-3.18.3 → thth-3.19.2}/thth/notification_route.py +0 -0
  581. {thth-3.18.3 → thth-3.19.2}/thth/oauth.py +0 -0
  582. {thth-3.18.3 → thth-3.19.2}/thth/oggformats.py +0 -0
  583. {thth-3.18.3 → thth-3.19.2}/thth/operations_handoff.py +0 -0
  584. {thth-3.18.3 → thth-3.19.2}/thth/plaza.py +0 -0
  585. {thth-3.18.3 → thth-3.19.2}/thth/plaza_cli.py +0 -0
  586. {thth-3.18.3 → thth-3.19.2}/thth/plaza_from.py +0 -0
  587. {thth-3.18.3 → thth-3.19.2}/thth/plaza_moments.py +0 -0
  588. {thth-3.18.3 → thth-3.19.2}/thth/plaza_observe.py +0 -0
  589. {thth-3.18.3 → thth-3.19.2}/thth/plaza_reads.py +0 -0
  590. {thth-3.18.3 → thth-3.19.2}/thth/plaza_redact.py +0 -0
  591. {thth-3.18.3 → thth-3.19.2}/thth/postid.py +0 -0
  592. {thth-3.18.3 → thth-3.19.2}/thth/private_store.py +0 -0
  593. {thth-3.18.3 → thth-3.19.2}/thth/pulse.py +0 -0
  594. {thth-3.18.3 → thth-3.19.2}/thth/queuefile.py +0 -0
  595. {thth-3.18.3 → thth-3.19.2}/thth/reaction_cli.py +0 -0
  596. {thth-3.18.3 → thth-3.19.2}/thth/reactions.py +0 -0
  597. {thth-3.18.3 → thth-3.19.2}/thth/read_coordination.py +0 -0
  598. {thth-3.18.3 → thth-3.19.2}/thth/read_window.py +0 -0
  599. {thth-3.18.3 → thth-3.19.2}/thth/redact.py +0 -0
  600. {thth-3.18.3 → thth-3.19.2}/thth/refusals.py +0 -0
  601. {thth-3.18.3 → thth-3.19.2}/thth/remote.py +0 -0
  602. {thth-3.18.3 → thth-3.19.2}/thth/replies.py +0 -0
  603. {thth-3.18.3 → thth-3.19.2}/thth/report_details.py +0 -0
  604. {thth-3.18.3 → thth-3.19.2}/thth/report_http.py +0 -0
  605. {thth-3.18.3 → thth-3.19.2}/thth/report_inbox.py +0 -0
  606. {thth-3.18.3 → thth-3.19.2}/thth/report_isolation.py +0 -0
  607. {thth-3.18.3 → thth-3.19.2}/thth/report_service.py +0 -0
  608. {thth-3.18.3 → thth-3.19.2}/thth/report_timeline.py +0 -0
  609. {thth-3.18.3 → thth-3.19.2}/thth/retract_cli.py +0 -0
  610. {thth-3.18.3 → thth-3.19.2}/thth/scopes.py +0 -0
  611. {thth-3.18.3 → thth-3.19.2}/thth/secrets_fs.py +0 -0
  612. {thth-3.18.3 → thth-3.19.2}/thth/selfupdate.py +0 -0
  613. {thth-3.18.3 → thth-3.19.2}/thth/server_files.py +0 -0
  614. {thth-3.18.3 → thth-3.19.2}/thth/server_reads.py +0 -0
  615. {thth-3.18.3 → thth-3.19.2}/thth/stop_observation.py +0 -0
  616. {thth-3.18.3 → thth-3.19.2}/thth/study_cli.py +0 -0
  617. {thth-3.18.3 → thth-3.19.2}/thth/study_report.py +0 -0
  618. {thth-3.18.3 → thth-3.19.2}/thth/systemd_gen.py +0 -0
  619. {thth-3.18.3 → thth-3.19.2}/thth/tags.py +0 -0
  620. {thth-3.18.3 → thth-3.19.2}/thth/thread_read.py +0 -0
  621. {thth-3.18.3 → thth-3.19.2}/thth/threadrun.py +0 -0
  622. {thth-3.18.3 → thth-3.19.2}/thth/threads_read_cli.py +0 -0
  623. {thth-3.18.3 → thth-3.19.2}/thth/threadshape.py +0 -0
  624. {thth-3.18.3 → thth-3.19.2}/thth/timer_cleanup.py +0 -0
  625. {thth-3.18.3 → thth-3.19.2}/thth/tool_version.py +0 -0
  626. {thth-3.18.3 → thth-3.19.2}/thth/topic_advice.py +0 -0
  627. {thth-3.18.3 → thth-3.19.2}/thth/topic_cli.py +0 -0
  628. {thth-3.18.3 → thth-3.19.2}/thth/topic_models.py +0 -0
  629. {thth-3.18.3 → thth-3.19.2}/thth/topic_store.py +0 -0
  630. {thth-3.18.3 → thth-3.19.2}/thth/topics.py +0 -0
  631. {thth-3.18.3 → thth-3.19.2}/thth/unanswered.py +0 -0
  632. {thth-3.18.3 → thth-3.19.2}/thth/vorbisformats.py +0 -0
  633. {thth-3.18.3 → thth-3.19.2}/thth/watch_cli.py +0 -0
  634. {thth-3.18.3 → thth-3.19.2}/thth/where_cli.py +0 -0
  635. {thth-3.18.3 → thth-3.19.2}/thth/where_keep.py +0 -0
  636. {thth-3.18.3 → thth-3.19.2}/thth/where_suggest.py +0 -0
  637. {thth-3.18.3 → thth-3.19.2}/thth/who_cli.py +0 -0
  638. {thth-3.18.3 → thth-3.19.2}/thth/worker.py +0 -0
  639. {thth-3.18.3 → thth-3.19.2}/thth/worker_version.py +0 -0
  640. {thth-3.18.3 → thth-3.19.2}/thth/writeback.py +0 -0
  641. {thth-3.18.3 → thth-3.19.2}/thth/x_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: thth
3
- Version: 3.18.3
3
+ Version: 3.19.2
4
4
  Summary: 承認済みの投稿だけを投げる門(Threads・Bluesky・Mastodon)。人が承認し、記録は利用者の git に残る。
5
5
  Project-URL: Homepage, https://thth.me
6
6
  Project-URL: Source, https://github.com/aokings/thth
@@ -47,6 +47,8 @@ English: [README.en.md](README.en.md) · サイト: https://thth.me · 文書の
47
47
  - **再投稿といいね**: `thth repost`・`unrepost`・`like`・`unlike`(3.15.0 から)。Threads は再投稿だけ(Threads の API にいいねが無い)。Bluesky は両方。Mastodon と X のいいねは、そのアカウントを認可し直してから([リリースノート 3.15.0](docs/リリースノート_3.15.0_2026-10-09.md))。
48
48
  - **検索の語ごとの数を残す・絞る**(3.18.0): `thth where … --also|--aggregate --keep` で語ごとの数だけを日付つきで残し(5 未満は欠測・本文や名前は残さない)、`thth where-log <project> [--budget N --medium x]` で当たり率と翌日の配り直しを見ます。`--ja`・`--question`・`--no-replies` で表示を絞ります(X の `--ja` は検索に `lang:ja` を足して読む本数を減らす)([リリースノート 3.18.0](docs/リリースノート_3.18.0_2026-10-12.md))。
49
49
  - **X の非公開リスト**: `thth list create|add|remove|show`(3.17.0 から・X だけ)。公開のリストは作らない。足す・外すは人が選んだ少数だけ(1 回 10 人まで)。アカウントを認可し直してから([リリースノート 3.17.0](docs/リリースノート_3.17.0_2026-10-12.md))。
50
+ - **X のコミュニティ**: `thth community search <account> <語…>` で探し、`thth send <account> --community <id>` か queue の front-matter `community_id:` で出す(3.19.0 から・X だけ)。参加は X の画面で先に(API に参加の口は無い)。返信とは同時に使えない。各コミュニティの規則は人が読んで守る([リリースノート 3.19.0](docs/リリースノート_3.19.0_2026-10-13.md))。
51
+ - **X のトレンドと語ごとの投稿数**: `thth trends <account> [--woeid N] [--max N]`(既定は日本)と `thth counts <account> <語> [--granularity hour|day]`(直近 7 日)(3.19.0 から・X だけ・1 回の有償の読み取り・保存しない)。
50
52
 
51
53
  ## はじめ方
52
54
 
@@ -107,13 +109,14 @@ MCP の道具は CLI の写しで、同じ `thth` コマンドを呼ぶだけで
107
109
 
108
110
  `thth --help` で各コマンドの説明が出ます。
109
111
 
110
- 動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`repost`・`unrepost`・`like`・`unlike`・`list`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
112
+ 動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
111
113
 
112
114
  ## 版と配布
113
115
 
114
116
  - 版の正本は `thth/VERSION` です。手元の版は `thth --version` で確かめます。
115
117
  - `main` への push は保存だけです。`release` を進めると運営のサーバーに出て、版の tag を push すると PyPI と MCP registry に出ます。
116
118
  - 依存は 0 です。入口は `thth` と `thth-mcp` の 2 つです。
119
+ - AI エージェント向けの試用の記録: [headlesson の THTH のページ](https://headlesson.com/apps/thth)(THTH と同じ運営)。3.15.0 の導入と `--help` を 2026-10-11 に確かめた記録で、投稿と予約は試していません。
117
120
 
118
121
  ## ライセンス
119
122
 
@@ -23,6 +23,8 @@ English: [README.en.md](README.en.md) · サイト: https://thth.me · 文書の
23
23
  - **再投稿といいね**: `thth repost`・`unrepost`・`like`・`unlike`(3.15.0 から)。Threads は再投稿だけ(Threads の API にいいねが無い)。Bluesky は両方。Mastodon と X のいいねは、そのアカウントを認可し直してから([リリースノート 3.15.0](docs/リリースノート_3.15.0_2026-10-09.md))。
24
24
  - **検索の語ごとの数を残す・絞る**(3.18.0): `thth where … --also|--aggregate --keep` で語ごとの数だけを日付つきで残し(5 未満は欠測・本文や名前は残さない)、`thth where-log <project> [--budget N --medium x]` で当たり率と翌日の配り直しを見ます。`--ja`・`--question`・`--no-replies` で表示を絞ります(X の `--ja` は検索に `lang:ja` を足して読む本数を減らす)([リリースノート 3.18.0](docs/リリースノート_3.18.0_2026-10-12.md))。
25
25
  - **X の非公開リスト**: `thth list create|add|remove|show`(3.17.0 から・X だけ)。公開のリストは作らない。足す・外すは人が選んだ少数だけ(1 回 10 人まで)。アカウントを認可し直してから([リリースノート 3.17.0](docs/リリースノート_3.17.0_2026-10-12.md))。
26
+ - **X のコミュニティ**: `thth community search <account> <語…>` で探し、`thth send <account> --community <id>` か queue の front-matter `community_id:` で出す(3.19.0 から・X だけ)。参加は X の画面で先に(API に参加の口は無い)。返信とは同時に使えない。各コミュニティの規則は人が読んで守る([リリースノート 3.19.0](docs/リリースノート_3.19.0_2026-10-13.md))。
27
+ - **X のトレンドと語ごとの投稿数**: `thth trends <account> [--woeid N] [--max N]`(既定は日本)と `thth counts <account> <語> [--granularity hour|day]`(直近 7 日)(3.19.0 から・X だけ・1 回の有償の読み取り・保存しない)。
26
28
 
27
29
  ## はじめ方
28
30
 
@@ -83,13 +85,14 @@ MCP の道具は CLI の写しで、同じ `thth` コマンドを呼ぶだけで
83
85
 
84
86
  `thth --help` で各コマンドの説明が出ます。
85
87
 
86
- 動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`repost`・`unrepost`・`like`・`unlike`・`list`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
88
+ 動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
87
89
 
88
90
  ## 版と配布
89
91
 
90
92
  - 版の正本は `thth/VERSION` です。手元の版は `thth --version` で確かめます。
91
93
  - `main` への push は保存だけです。`release` を進めると運営のサーバーに出て、版の tag を push すると PyPI と MCP registry に出ます。
92
94
  - 依存は 0 です。入口は `thth` と `thth-mcp` の 2 つです。
95
+ - AI エージェント向けの試用の記録: [headlesson の THTH のページ](https://headlesson.com/apps/thth)(THTH と同じ運営)。3.15.0 の導入と `--help` を 2026-10-11 に確かめた記録で、投稿と予約は試していません。
93
96
 
94
97
  ## ライセンス
95
98
 
@@ -62,6 +62,14 @@ THTH は CLI ツール。あなた(エージェント)が使う MCP の道
62
62
 
63
63
  `thth list create <account> <名前> [--description …] --by <名前>`・`thth list add|remove <account> <list_id> <id か @handle…> --by <名前>`・`thth list show <account> <list_id> [--limit N]`(MCP には無い)。X のアカウントならどれでも(今は asmon-kanto-x と kopicha-x)・**使う前に各アカウントで `thth auth <account> --by <名前>` を打ち直す**。**非公開リストだけ**(公開は作れない)。足すのは**人が選んだ少数だけ**——1 回 10 人まで、検索結果から機械的に足さない(X の決まりで bulk・無差別の追加は不可)。足された相手に X が通知するかは未確認。書き込みは production: true の口座だけ・費用は月の X 予算(作る 0.010・足す/外す 0.005 USD、@handle の id 引き 0.010)。`show` は `where` と同じ有償の読み取り(1 本 0.005・1 日 60 本に数える・既定 10 本・最大 25)で、本文は返すだけで保存しない。断り: `scope_missing`(`thth auth <account> --by <名前>` で認可し直す)・`too_many_members`・`unsupported_on_platform`(X 以外)。
64
64
 
65
+ ## X のコミュニティ(3.19.0)
66
+
67
+ `thth community search <account> <語…> [--limit N] [--json]`(MCP には無い)で探し、`thth send <account> --community <id>` か queue の front-matter `community_id: <id>` で出す。X だけ・認可のやり直しは不要。探すのは有償の読み取り(1 件 0.005 USD・月の X 予算・1 日 60 本には数えない・既定 10 件・最大 25・保存しない)。`community_id` は digest/承認の指紋に入る。返信(reply_to・reply_to_file)と同時には使えない・連投には書けない。**参加は X の画面で先に**(API に参加の口も「参加しているか」の欄も無い)——参加していなければ X の断りが `x_unknown_refusal(…)` で残る。**各コミュニティの規則(宣伝の禁止など)は人が読んで守る**。所有者に頼まれたコミュニティへ、人が選んだ本文を 1 本ずつ出すだけ——検索の結果へ機械的に出さない・同じ本文を複数のコミュニティへ流さない(X の自動化の決まりで bulk・無差別は不可)。断り: `unsupported_on_platform`(X 以外)・`community_id_invalid`・lint の `invalid_publish_option`。
68
+
69
+ ## X のトレンドと語ごとの投稿数(3.19.0)
70
+
71
+ `thth trends <account> [--woeid N] [--max N]`(既定は日本・20 件・1 回 0.010 USD)・`thth counts <account> <語> [--granularity hour|day]`(直近 7 日・1 回 0.005 USD)(MCP には無い)。X だけ・要求は 1 回・返すだけで保存しない・月の X 予算に入り 1 日 60 本には数えない。話題選びの材料に使う——トレンドの語へ機械的に投稿しない。いまのトークンで通るかは未確認(断りは X の文面が短く残る)。
72
+
65
73
  ## 何を拒むか
66
74
 
67
75
  - **手元の台帳を使う実行の、`--confirm` の無い本番。** digest の食い違う本番。承認後に本文が変わった下書き
@@ -780,7 +780,11 @@ def test_本物の台帳でrc0でcannot_sayが出る(tmp_path):
780
780
  assert proc.returncode == 0, proc.stderr
781
781
  answer = json.loads(proc.stdout)
782
782
  assert answer["provenance"]["source"] == "local"
783
- assert answer["cannot_say"], "手元の水で言い切ってしまっている"
783
+ # 2026-10-13: kopicha の 30 日の群が n=79 になり、全部の指標が min_n を超えて
784
+ # cannot_say が空になった(それが正直な答え)。見るのは「中央値を言えない指標が
785
+ # あるなら cannot_say も空でない」こと。
786
+ if any(m["median"] is None for m in answer["expected"].values()):
787
+ assert answer["cannot_say"], "言えない指標があるのに言い切ってしまっている"
784
788
  # 本物の水は日々増えるので、中央値の有無そのものは固定できない(2026-09-23:
785
789
  # kopicha の 24h の観測が n=24 になり、中央値 0 が正直な答えになった)。見るのは
786
790
  # 規約 2「n が min_n に満たなければ中央値を言わない」が本物の水でも守られること。
@@ -58,7 +58,9 @@ COMMANDS = '''lint|preview|approve|account|revoke|posts|replies|measured|threads
58
58
  # 3.17.0: X の非公開リスト。
59
59
  'list create', 'list add', 'list remove', 'list show',
60
60
  # 3.18.0: where … --keep で残した数を読む口。
61
- 'where-log']
61
+ 'where-log',
62
+ # 3.19.0: X のコミュニティを探す。
63
+ 'community search', 'trends', 'counts']
62
64
 
63
65
 
64
66
  def test_json_table_covers_every_parser():
@@ -0,0 +1,242 @@
1
+ """3.19.2: X がアカウント側の断り(x_not_permitted)を返したら、自動の投稿を止める。
2
+
3
+ 10/14 08:33 から kopicha-x の予約投稿が `POST /2/tweets` で 403 を返し続け、timer が
4
+ 10 分ごとに同じ承認済み原稿を投げ直して 61 回断られた。ここで確かめること:
5
+
6
+ - 1 回断られたら `state/<account>/publish_hold/held.json` に印を置き、次の run は
7
+ X に何も投げない(runs にも積もらない)。死活通知の理由は `x_not_permitted`、
8
+ 次の一手は `fix_account_then_resume`。
9
+ - 原稿ごとの断り(x_reply_not_engaged・x_duplicate_content)と、ほかの媒体は止めない。
10
+ - 手の `thth send` は止まっている間 dry-run でも断る。
11
+ - `thth account resume <口座> --by <名前>` で戻る(`--by` なしは断る)。
12
+ - 印が壊れていたら止まっている側に倒す。
13
+ - board・morning・`thth account status` に出る。
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import io
18
+ import json
19
+ import os
20
+ import urllib.error
21
+
22
+ import pytest
23
+
24
+ from thth import accounts as accounts_mod
25
+ from thth import core, healthcheck, publish_hold, runs
26
+ from thth.adapters import x as x_adapter
27
+ from tests.conftest import write_queue_file
28
+ from tests.test_fake_api import NOW
29
+ from tests.test_v214_x_media import set_post_budget
30
+
31
+ NOT_PERMITTED = (b'{"title":"Forbidden","type":"about:blank","status":403,'
32
+ b'"detail":"You are not permitted to perform this action."}')
33
+ NOT_ENGAGED = (b'{"title":"Forbidden","type":"about:blank","status":403,"detail":'
34
+ b'"Reply to this conversation is not allowed because you have not been mentioned '
35
+ b'or otherwise engaged by the author of the post you are replying to."}')
36
+
37
+
38
+ @pytest.fixture
39
+ def x_account(isolated_account_factory, monkeypatch):
40
+ account = isolated_account_factory(production=True, media="x", handle="demo")
41
+ write_queue_file(account["queue_dir"], "a.md", body="## x\n\n本文です。\n", media="x")
42
+ set_post_budget(10)
43
+ return account
44
+
45
+
46
+ @pytest.fixture
47
+ def wire(monkeypatch):
48
+ """`POST /2/tweets` を数え、`state["body"]` の 403 を返す(X には届かない)。"""
49
+ state = {"tweets": 0, "body": NOT_PERMITTED}
50
+
51
+ def request(adapter, method, path, **kwargs):
52
+ if path == "/2/tweets":
53
+ state["tweets"] += 1
54
+ if state["body"] is None:
55
+ return 201, {"data": {"id": str(1900000000000000000 + state["tweets"]), "text": "x"}}
56
+ raise urllib.error.HTTPError(adapter.base_url + path, 403, "Forbidden", {},
57
+ io.BytesIO(state["body"]))
58
+ raise AssertionError("unexpected request " + path)
59
+ monkeypatch.setattr(x_adapter, "request", request)
60
+ return state
61
+
62
+
63
+ def factory(name):
64
+ def make(cfg, token):
65
+ adapter = x_adapter.XAdapter(base_url="https://api.x.invalid", access_token="t" * 30,
66
+ user_id="123", username="demo")
67
+ adapter.auth_account = name
68
+ return adapter
69
+ return make
70
+
71
+
72
+ def throw(account):
73
+ lines = []
74
+ result = core.throw_once(account["name"], production_flag=True,
75
+ adapter_factory=factory(account["name"]), now=NOW, log=lines.append)
76
+ return result, lines
77
+
78
+
79
+ def state_of(account):
80
+ return accounts_mod.state_dir_for(account["name"])
81
+
82
+
83
+ # ----- 断りの符丁 ------------------------------------------------------------------
84
+
85
+ @pytest.mark.parametrize("error,code", [
86
+ ("x_publish_http_403: x_not_permitted", "x_not_permitted"),
87
+ ("media_publishing_http_403: x_not_permitted", "x_not_permitted"),
88
+ ("x_publish_http_403: x_reply_not_engaged", None),
89
+ ("x_publish_http_403: x_duplicate_content", None),
90
+ ("x_publish_http_403", None),
91
+ ("provider_rate_limited", None),
92
+ ("x_not_permitted", None),
93
+ (None, None),
94
+ ])
95
+ def test_refusal_code_reads_only_the_account_refusal_after_a_4xx(error, code):
96
+ assert publish_hold.refusal_code(error) == code
97
+
98
+
99
+ def test_other_media_never_hold(x_account):
100
+ cfg = {"media": "threads"}
101
+ assert publish_hold.note_refusal(x_account["name"], cfg, "x_publish_http_403: x_not_permitted") is None
102
+ assert publish_hold.held(x_account["name"]) is None
103
+
104
+
105
+ # ----- timer の run ----------------------------------------------------------------
106
+
107
+ def test_first_refusal_holds_and_the_next_run_does_not_post(x_account, wire):
108
+ first, lines = throw(x_account)
109
+ assert first.action == "post" and first.exit_code == 1
110
+ assert first.error == "x_publish_http_403: x_not_permitted"
111
+ assert wire["tweets"] == 1
112
+ row = publish_hold.held(x_account["name"])
113
+ assert row["reason"] == "x_not_permitted" and row["file"] == "a.md" and row["held_at"]
114
+ assert any("自動の投稿を止めています" in line for line in lines)
115
+ rows_before = len(runs.read_runs(state_of(x_account)))
116
+
117
+ second, lines = throw(x_account)
118
+ assert wire["tweets"] == 1 # 2 回目は X に何も投げない
119
+ assert second.action == "publish_held" and second.exit_code == 2
120
+ assert second.error == "x_not_permitted" and second.file == "a.md"
121
+ assert len(runs.read_runs(state_of(x_account))) == rows_before # runs に積もらない
122
+ assert any("thth account resume" in line for line in lines)
123
+
124
+ for result in (first, second):
125
+ diag = healthcheck.diagnostic(x_account["name"], "fail", state_dir=state_of(x_account),
126
+ result=result)
127
+ assert diag.reason_code == "x_not_permitted"
128
+ assert diag.next_action_code == "fix_account_then_resume"
129
+ assert "thth account resume" in diag.next_action
130
+ assert healthcheck.has_blocking_state(x_account["name"], state_of(x_account)) is True
131
+ # 運用通知は同じ原稿の 1 つの事象として束ねる(止めたあとの run で 2 通目を出さない)。
132
+ from thth import incident
133
+ cfg = accounts_mod.load_account(x_account["name"])
134
+ assert incident.source(cfg, state_of(x_account), first) == "docs/sns/queue/a.md"
135
+ assert incident.source(cfg, state_of(x_account), second) == "docs/sns/queue/a.md"
136
+
137
+
138
+ def test_rehearsal_still_shows_what_would_be_posted(x_account, wire):
139
+ throw(x_account)
140
+ lines = []
141
+ result = core.throw_once(x_account["name"], production_flag=False,
142
+ adapter_factory=factory(x_account["name"]), now=NOW, log=lines.append)
143
+ assert result.mode == "rehearsal" and result.action == "skip"
144
+ assert any("自動の投稿を止めています" in line for line in lines)
145
+ assert wire["tweets"] == 1
146
+
147
+
148
+ @pytest.mark.parametrize("body", [NOT_ENGAGED, b'{"detail":"duplicate content"}'])
149
+ def test_per_draft_refusals_do_not_hold(x_account, wire, body):
150
+ wire["body"] = body
151
+ first, _ = throw(x_account)
152
+ assert first.action == "post" and "x_not_permitted" not in first.error
153
+ assert publish_hold.held(x_account["name"]) is None
154
+ throw(x_account)
155
+ assert wire["tweets"] == 2 # 原稿ごとの断りは今までどおり次の run がまた試す
156
+
157
+
158
+ def test_unreadable_hold_is_held(x_account, wire):
159
+ folder = os.path.join(state_of(x_account), "publish_hold")
160
+ os.makedirs(folder, mode=0o700)
161
+ with open(os.path.join(folder, publish_hold.HOLD_FILE), "w", encoding="utf-8") as f:
162
+ f.write("{broken")
163
+ os.chmod(os.path.join(folder, publish_hold.HOLD_FILE), 0o600)
164
+ result, _ = throw(x_account)
165
+ assert result.action == "publish_held" and result.error == "publish_hold_unreadable"
166
+ assert wire["tweets"] == 0
167
+ diag = healthcheck.diagnostic(x_account["name"], "fail", state_dir=state_of(x_account), result=result)
168
+ assert diag.reason_code == "publish_hold_unreadable"
169
+ assert diag.next_action_code == "fix_account_then_resume"
170
+
171
+
172
+ # ----- 再開 ------------------------------------------------------------------------
173
+
174
+ def test_resume_needs_by_and_then_the_run_posts_again(x_account, wire, capsys):
175
+ from thth import cli
176
+ throw(x_account)
177
+ assert cli.main(["account", "resume", x_account["name"]]) == 2
178
+ assert publish_hold.held(x_account["name"]) is not None
179
+ assert cli.main(["account", "resume", x_account["name"], "--by", "masaru", "--json"]) == 0
180
+ out = json.loads(capsys.readouterr().out.strip().splitlines()[-1])
181
+ assert out == {"account": x_account["name"], "resumed": False, "publish_resumed": True}
182
+ assert publish_hold.held(x_account["name"]) is None
183
+
184
+ wire["body"] = None # X の画面で直った
185
+ result, _ = throw(x_account)
186
+ assert result.action == "post" and result.exit_code == 0 and result.post_id
187
+ assert wire["tweets"] == 2
188
+
189
+
190
+ def test_resume_while_still_refused_stops_again_after_one_request(x_account, wire):
191
+ from thth import cli
192
+ throw(x_account)
193
+ assert cli.main(["account", "resume", x_account["name"], "--by", "masaru"]) == 0
194
+ throw(x_account)
195
+ throw(x_account)
196
+ assert wire["tweets"] == 2 # 再開後に 1 回だけ試し、また止まる
197
+ assert publish_hold.held(x_account["name"])["reason"] == "x_not_permitted"
198
+
199
+
200
+ # ----- 手の thth send -------------------------------------------------------------
201
+
202
+ def test_send_is_refused_while_held_even_on_dry_run(x_account, wire):
203
+ throw(x_account)
204
+ lines = []
205
+ result = core.send_once(x_account["name"], text="手で出す", log=lines.append,
206
+ adapter_factory=factory(x_account["name"]))
207
+ assert result.action == "publish_held" and result.exit_code == 2 and result.digest is None
208
+ assert any("thth account resume" in line for line in lines)
209
+ assert wire["tweets"] == 1
210
+
211
+
212
+ def test_send_refusal_also_holds(x_account, wire):
213
+ dry = core.send_once(x_account["name"], text="手で出す", adapter_factory=factory(x_account["name"]))
214
+ result = core.send_once(x_account["name"], text="手で出す", production_flag=True, confirm=dry.digest,
215
+ adapter_factory=factory(x_account["name"]))
216
+ assert result.action == "post" and result.exit_code == 1
217
+ assert publish_hold.held(x_account["name"])["via"] == "send"
218
+
219
+
220
+ # ----- 見える所 -------------------------------------------------------------------
221
+
222
+ def test_board_morning_and_status_say_it(x_account, wire, capsys):
223
+ from thth import account_settings, morning, report
224
+ from types import SimpleNamespace
225
+ throw(x_account)
226
+ rows = {row["account"]: row for row in report.board_summary(now=NOW)["accounts"]}
227
+ hold = rows[x_account["name"]]["publish_hold"]
228
+ assert hold["reason"] == "x_not_permitted" and "thth account resume" in hold["message"]
229
+
230
+ value = morning._publish_hold_row(x_account["name"])
231
+ assert value["reason"] == "x_not_permitted"
232
+ assert value["next_action_code"] == "fix_account_then_resume"
233
+
234
+ from thth import cli
235
+ capsys.readouterr()
236
+ assert cli.main(["board"]) == 0
237
+ assert "自動の投稿を止めています" in capsys.readouterr().out
238
+ cli.main(["morning", x_account["name"], "--no-world", "--no-mark"])
239
+ assert "自動の投稿を止めています: x_not_permitted" in capsys.readouterr().out
240
+ assert account_settings.cmd_status(SimpleNamespace(name=x_account["name"], rest=None, json=False)) == 0
241
+ out = capsys.readouterr().out
242
+ assert "自動の投稿を止めています" in out and "動いています" not in out