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.
- {thth-3.18.3 → thth-3.19.2}/PKG-INFO +5 -2
- {thth-3.18.3 → thth-3.19.2}/README.md +4 -1
- {thth-3.18.3 → thth-3.19.2}/skills/thth/SKILL.md +8 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_ask.py +5 -1
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_json_contract.py +3 -1
- thth-3.19.2/tests/test_v3192_publish_hold.py +242 -0
- thth-3.19.2/tests/test_x_community.py +427 -0
- thth-3.19.2/tests/test_x_trends_counts.py +188 -0
- thth-3.19.2/thth/VERSION +1 -0
- {thth-3.18.3 → thth-3.19.2}/thth/account_cli.py +2 -1
- {thth-3.18.3 → thth-3.19.2}/thth/account_settings.py +25 -7
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/base.py +6 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/x.py +273 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/x_media.py +6 -0
- {thth-3.18.3 → thth-3.19.2}/thth/admin_log.py +4 -1
- {thth-3.18.3 → thth-3.19.2}/thth/approval.py +31 -8
- {thth-3.18.3 → thth-3.19.2}/thth/budget_x.py +94 -6
- {thth-3.18.3 → thth-3.19.2}/thth/bundle.py +4 -0
- {thth-3.18.3 → thth-3.19.2}/thth/cli.py +20 -0
- thth-3.19.2/thth/community_cli.py +143 -0
- {thth-3.18.3 → thth-3.19.2}/thth/core.py +64 -8
- {thth-3.18.3 → thth-3.19.2}/thth/fingerprint_golden.py +5 -0
- {thth-3.18.3 → thth-3.19.2}/thth/healthcheck.py +23 -0
- {thth-3.18.3 → thth-3.19.2}/thth/leave_gate.py +2 -1
- {thth-3.18.3 → thth-3.19.2}/thth/lint.py +32 -0
- {thth-3.18.3 → thth-3.19.2}/thth/morning.py +21 -0
- thth-3.19.2/thth/publish_hold.py +170 -0
- {thth-3.18.3 → thth-3.19.2}/thth/relay.py +3 -1
- {thth-3.18.3 → thth-3.19.2}/thth/report.py +12 -0
- {thth-3.18.3 → thth-3.19.2}/thth/runs.py +15 -0
- {thth-3.18.3 → thth-3.19.2}/thth/select.py +8 -0
- {thth-3.18.3 → thth-3.19.2}/thth/sent.py +9 -1
- {thth-3.18.3 → thth-3.19.2}/thth/server_writes.py +4 -0
- {thth-3.18.3 → thth-3.19.2}/thth/threadthrow.py +9 -0
- thth-3.19.2/thth/trends_cli.py +187 -0
- thth-3.18.3/thth/VERSION +0 -1
- {thth-3.18.3 → thth-3.19.2}/.gitignore +0 -0
- {thth-3.18.3 → thth-3.19.2}/LICENSE +0 -0
- {thth-3.18.3 → thth-3.19.2}/accounts.example/bluesky.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/accounts.example/mastodon.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/accounts.example/threads.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/accounts.example/x.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/bin/thth +0 -0
- {thth-3.18.3 → thth-3.19.2}/bin/thth-remote +0 -0
- {thth-3.18.3 → thth-3.19.2}/bin/thth-run +0 -0
- {thth-3.18.3 → thth-3.19.2}/mcp/server.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/pyproject.toml +0 -0
- {thth-3.18.3 → thth-3.19.2}/skills/thth-admin/SKILL.md +0 -0
- {thth-3.18.3 → thth-3.19.2}/systemd/thth@.service +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/__init__.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/conftest.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/coordination_snapshot.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/fixtures/GraphemeBreakTest-17.0.0.txt +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/fixtures/build_injection_eval.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/fixtures/callback/worker_responses.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/fixtures/injection_eval.json +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/fixtures/umami-bile.md +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/__init__.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_oauth_server.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_push_adapter.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_redirect_server.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_search_adapter.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_reader.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_status.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_threads_writes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/fake_x.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/hold_lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/hold_repo_lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/helpers/worker_probe.mjs +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_27_acceptance_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_account_name_check.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_account_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_accounts_dir.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_adapter_boundary.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_admin_http_mcp.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_admin_log.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_admin_notifications.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_admin_repairs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_admin_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_after_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_analytics_comparison.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_analytics_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_api_diagnostic.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_api_error_body.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_app_env_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_approval.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_approve_cmd.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_fifth_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_fourth_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_second_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_atlas_third_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit1_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit2_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_counterexamples.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_m1_semantics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_n1_depth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_b_r1_closure.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_v201.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_audit_v23_details.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_auth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_auth_identity_required.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_behind_remote.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_bluesky_adapter.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_bluesky_secret_scrub.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_board_needs_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_board_running.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_branch_replies.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_bundle.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_bundle_not_type_mismatch.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_charcount.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_cli_entrypoint.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_cli_help.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_cli_vm_path.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_collect.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_collect_engagements.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_collect_runs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_collect_sent.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_comparability.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_control_chars_refused.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_conversation_paging.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_count_for.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_docs_links.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_doctor.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_doctor_all_permissions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_doctor_next_step.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_duplicate_front_matter_keys.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_editorial_audit.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_editorial_n3_n4.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_engagements.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_external_acceptance.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_fake_api.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_form_spec.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_form_spec_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_forms.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_fresh_install.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_front_matter_injection.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_healthcheck_notifications.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_hypotheses.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_hypothesis_boundaries.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_hypothesis_units.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_impact_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_inbox_granted_scopes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_incident_notifications.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_independent_thread_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_independent_topic_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_independent_topic_review_r2.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_inflight.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_inflight_tag_body_hash.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_jst.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_lint.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_list_projections.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_llm_trial.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_llm_trial_engage.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_m2_independent.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_maintain.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_mastodon_adapter.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_mastodon_visibility.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_max_per_run.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_mcp.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_mcp_robustness.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_measured.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_media_accounts.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_media_next_steps.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_media_roundtrip.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_mismatch_diagnostics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_n5_reply_null_element.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_n6_replies_incomplete_ledger.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_n7_doctor_error_body.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_no_limits.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_observation_provenance.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_operations_handoff.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_packaging.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_preview.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_production_mode.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_pull_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_pulse.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_queue.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_quiet_hours.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_r2_r4_r5.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_read_cli_bare_runtimeerror.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_reason_adoption.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_redact.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_redirect_token_leak.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_refresh.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_refresh_destination.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_rejudge_new.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_rejudge_r2_r3.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_replies.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_replies_refresh.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_repo_lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_repo_sync.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_report_checkout_import.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_report_http.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_report_isolation.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_report_service.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_retract_already_gone.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_reverse_audit.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_case_id_cluster_m2.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_case_id_cluster_r2.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_evidence_account.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_form_spec_and_case_id.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_provenance.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_review_records.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_revoke.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_roundtrip.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_run_missing_env.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_run_record_failclosed.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_runs_collected.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_runs_read_rows.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_schedule_multiple.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_schedule_view.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_scopes_source_requested.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_search_engage_targets.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_search_media_routes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_secret_value_redact.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_secrets_grep.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_security_small_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_select.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_selfupdate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_send.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_send_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_send_control_chars.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_send_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_send_visibility.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_sent_integrity.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_server_json.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_site.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_skill_doc.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_study_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_systemd.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_thread_publish.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_thread_read.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_threadrun.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_threads_read_permissions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_threadshape.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_thth_root.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_token_exists.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_token_scopes_record.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_token_set.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_advice.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_models.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_review_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_shelf_observers.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topic_store.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topics_record_concurrent.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_topics_tool.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_trial_frictions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_admin_transaction.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_approve_account.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_length.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_lock_wait.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_mastodon_scopes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_mentions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_post_urls.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_repo_paths.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_reposts.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_study_add.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_tool_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_unanswered.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_unanswered_scope.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_where_arguments.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_where_filters.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v210_who_arguments.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_auth_integration.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_authflow.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_bluesky_stdin.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_doctor_binding.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_mastodon_auth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v211_x_auth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_ask_coordination.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget_auth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_budget_mcp.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_deletion.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_gate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_providers.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_leave_token_safety.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_mastodon_guide.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_mcp_compat.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_missing_token.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_read_coordination.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_relay.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_server_writes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_token_parent.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v212_write_storage.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2131_send_dry_run.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2131_threads_publish_wait.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_send_inflight_hint.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_threads_create_timeout.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2132_threads_create_unknown.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_acceptance_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_adts_asf.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_attachment_kinds.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_external.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata_uri.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_metadata_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_record.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_record_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bluesky_webm_named.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_bmff_typed_metadata.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_budget_lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_capabilities.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_carryover_timeout.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_graphemes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_auth_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_bmff_audio.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_flac.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_gif.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_link.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_mp3.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_ogg_opus.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_ogg_vorbis.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_poll.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_primary_size_boundary.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_quote.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_thumbnail.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_wav.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_webm_audio.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_mastodon_webm_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_cleanup.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_formats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_foundation.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_prepared.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_relay.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_relay_refusals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_media_upload.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_review_followups.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_stage810_audit.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_static_diagnostics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_stop_observation.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_systemd_worker.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_ghost.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_gif.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_link.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_media_spoiler.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_poll.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_quote.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_quote_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_replies.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_text.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_text_spoiler.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_threads_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_transport_review.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_video_typed_metadata.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_vorbis_comment_boundary.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v213_webm_schema_boundary.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2141_draft_lint_reason.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v2141_managed_repo_umask.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v214_release_signing.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_adapter.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_auth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v214_x_posts_budget.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v21b_approved_writes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v28_tags.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_admin_approval.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_create.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_credential.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_limits.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3100_invite_worker.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v310_morning.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v310_search_timeout.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v310_watch_words.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3111_observe_counts_only.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3111_observe_no_world.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_leave_same_user.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_mastodon_retract.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_overdue.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_own_exclusion.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_morning_unanswered_window.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_notifications_guidance.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v311_replies_owned.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_activity.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_admin_write_reasons.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_guard.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3120_worker_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_leave_shared_token.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_own_handles_stopped.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_admin.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_channel.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_inbox.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v312_report_mcp_user.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_api_relay.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_invite_key.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_remote_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3140_server_reads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3142_browser_login.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_activity_push.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_cli_umask_leave.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_inflight_remote.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3143_managed_repo_recover.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v315_reactions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v317_run_lock_wait.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_json_names.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_map_timer.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_where_filters.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v3180_where_keep.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v31_analysis.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v31_collection.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_display.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_lint.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v320_reply_to_file_resolve.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v320_report_fixes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_fingerprint_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_held.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_held_names.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_last_refusals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_notification_route.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_observe.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_report_friction.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_report_words.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v330_reports_effect.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v331_inflight_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v331_listing_resolve.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v331_outbox_retention.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v331_publish_status.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v331_self_resolve.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_fields.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_mcp.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_morning.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_observe.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_open.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_open_confirm.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_reply.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v340_plaza_store.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_nodes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_observe.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_plaza.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_retention.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_self.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_show.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v350_map_world.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v351_leave_timers.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v351_plaza_open_holes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v351_who_owned.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_analytics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_observe_map.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_plaza.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_record.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_goal_send.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v360_report_timeline.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_account_self_healing.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_approve_pending.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_click_attribution.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_collection_stale_basis.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_follow_comparison.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_local_path.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_weekly_goals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_aggregate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_also.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v370_where_zero.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_digest.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_from.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_mcp.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_moments.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_owner.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_received.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v380_plaza_triggers.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v381_plaza_visibility_default.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v382_confirm_file.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v382_first_stage_not_refusal.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v382_reader_lock_and_push_pending.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v382_sync_without_fetch_head.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v390_docs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v390_per_post_clicks.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v390_where_rate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v390_where_suggest.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_v391_plaza_text_numbers.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_value_domains_shown.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_where_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_where_threads_tag_author.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_who_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_writeback_rebase.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_writeback_validate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_x_list.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_x_metrics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_x_owned_metrics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_x_search_thread.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/tests/test_x_token_autorefresh.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/__init__.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/__main__.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/_grapheme_data.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/account_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/accounts.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/activity.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/__init__.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_mastodon.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_threads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/auth_x.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/bluesky_video.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/mastodon.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/mastodon_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/threads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/adapters/threads_media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/admin_diagnose.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/admin_notifications.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/admin_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/after_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_clicks.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_comparison.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_goals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_shapes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_threads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/analytics_weekly.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/api_diagnostic.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/api_requests.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/appconfig.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/appenv.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/approve_pending.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/ask.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/ask_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/audioformats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/authclients.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/authflow.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/authpassword.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/bluesky_metadata.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/budget_x_posts.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/click_attribution.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/collect.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/collection_context.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/collection_status.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/deletion.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/doctor.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/ebmlaudio.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/ebmlvideo.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/engagements.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/flacformats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/forms.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/goals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/graphemes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/guard.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/handoff_cursor.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/httpsafe.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/incident.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/inflight.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/inflight_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/inflight_resolve.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/invites.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/jst.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/leave.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/list_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/lock.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/maintain.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/managed_repo.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/map_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/map_store.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/map_view.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/map_world.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/measured.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media_capabilities.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media_cleanup.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media_delivery.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media_relay.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/media_uploads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/mediaformats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/mpeg_audio.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/notification_route.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/oauth.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/oggformats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/operations_handoff.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_from.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_moments.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_observe.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_reads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/plaza_redact.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/postid.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/private_store.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/pulse.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/queuefile.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/reaction_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/reactions.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/read_coordination.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/read_window.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/redact.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/refusals.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/remote.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/replies.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_details.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_http.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_inbox.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_isolation.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_service.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/report_timeline.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/retract_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/scopes.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/secrets_fs.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/selfupdate.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/server_files.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/server_reads.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/stop_observation.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/study_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/study_report.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/systemd_gen.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/tags.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/thread_read.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/threadrun.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/threads_read_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/threadshape.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/timer_cleanup.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/tool_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/topic_advice.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/topic_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/topic_models.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/topic_store.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/topics.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/unanswered.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/vorbisformats.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/watch_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/where_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/where_keep.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/where_suggest.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/who_cli.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/worker.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/worker_version.py +0 -0
- {thth-3.18.3 → thth-3.19.2}/thth/writeback.py +0 -0
- {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.
|
|
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
|
-
|
|
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
|