thth 2.2.0__tar.gz → 2.3.0__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-2.2.0 → thth-2.3.0}/PKG-INFO +6 -10
- {thth-2.2.0 → thth-2.3.0}/README.md +5 -9
- {thth-2.2.0 → thth-2.3.0}/mcp/server.py +217 -3
- thth-2.3.0/skills/thth/SKILL.md +121 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_adapter_boundary.py +4 -1
- thth-2.3.0/tests/test_after_cli.py +205 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_app_env_cli.py +5 -1
- {thth-2.2.0 → thth-2.3.0}/tests/test_approve_cmd.py +39 -2
- {thth-2.2.0 → thth-2.3.0}/tests/test_bluesky_adapter.py +122 -4
- thth-2.3.0/tests/test_cli_help.py +87 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_docs_links.py +26 -0
- thth-2.3.0/tests/test_engagements.py +208 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_fake_api.py +11 -1
- thth-2.3.0/tests/test_llm_trial_engage.py +410 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_mastodon_adapter.py +136 -3
- {thth-2.2.0 → thth-2.3.0}/tests/test_mastodon_visibility.py +23 -0
- thth-2.3.0/tests/test_mcp.py +324 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_packaging.py +25 -20
- thth-2.3.0/tests/test_runs_read_rows.py +172 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_search_engage_targets.py +24 -4
- {thth-2.2.0 → thth-2.3.0}/tests/test_selfupdate.py +32 -0
- thth-2.3.0/tests/test_skill_doc.py +101 -0
- thth-2.3.0/tests/test_thread_read.py +333 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_threads_read_permissions.py +32 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_review_fixes.py +13 -1
- thth-2.3.0/tests/test_where_cli.py +311 -0
- thth-2.3.0/tests/test_who_cli.py +327 -0
- thth-2.3.0/thth/VERSION +1 -0
- {thth-2.2.0 → thth-2.3.0}/thth/accounts.py +7 -2
- {thth-2.2.0 → thth-2.3.0}/thth/adapters/base.py +33 -0
- {thth-2.2.0 → thth-2.3.0}/thth/adapters/bluesky.py +121 -1
- {thth-2.2.0 → thth-2.3.0}/thth/adapters/mastodon.py +114 -1
- {thth-2.2.0 → thth-2.3.0}/thth/adapters/threads.py +44 -0
- thth-2.3.0/thth/after_cli.py +342 -0
- {thth-2.2.0 → thth-2.3.0}/thth/cli.py +57 -9
- {thth-2.2.0 → thth-2.3.0}/thth/core.py +76 -5
- thth-2.3.0/thth/engagements.py +195 -0
- {thth-2.2.0 → thth-2.3.0}/thth/lint.py +20 -0
- thth-2.3.0/thth/runs.py +125 -0
- {thth-2.2.0 → thth-2.3.0}/thth/selfupdate.py +24 -0
- thth-2.3.0/thth/thread_read.py +415 -0
- {thth-2.2.0 → thth-2.3.0}/thth/threads_read_cli.py +6 -0
- thth-2.3.0/thth/where_cli.py +384 -0
- thth-2.3.0/thth/who_cli.py +401 -0
- thth-2.2.0/skills/thth/SKILL.md +0 -117
- thth-2.2.0/tests/helpers/share_ledger.py +0 -92
- thth-2.2.0/tests/test_mcp.py +0 -108
- thth-2.2.0/tests/test_share.py +0 -413
- thth-2.2.0/tests/test_share_safety.py +0 -239
- thth-2.2.0/tests/test_share_sync_concurrent.py +0 -93
- thth-2.2.0/thth/VERSION +0 -1
- thth-2.2.0/thth/runs.py +0 -65
- thth-2.2.0/thth/share.py +0 -666
- thth-2.2.0/thth/share_cli.py +0 -140
- {thth-2.2.0 → thth-2.3.0}/.gitignore +0 -0
- {thth-2.2.0 → thth-2.3.0}/LICENSE +0 -0
- {thth-2.2.0 → thth-2.3.0}/accounts.example/bluesky.json +0 -0
- {thth-2.2.0 → thth-2.3.0}/accounts.example/mastodon.json +0 -0
- {thth-2.2.0 → thth-2.3.0}/accounts.example/threads.json +0 -0
- {thth-2.2.0 → thth-2.3.0}/bin/thth +0 -0
- {thth-2.2.0 → thth-2.3.0}/bin/thth-remote +0 -0
- {thth-2.2.0 → thth-2.3.0}/bin/thth-run +0 -0
- {thth-2.2.0 → thth-2.3.0}/pyproject.toml +0 -0
- {thth-2.2.0 → thth-2.3.0}/systemd/thth@.service +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/__init__.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/conftest.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/fixtures/build_injection_eval.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/fixtures/callback/worker_responses.json +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/fixtures/injection_eval.json +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/fixtures/umami-bile.md +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/__init__.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_oauth_server.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_push_adapter.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_redirect_server.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_search_adapter.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_threads_reader.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/fake_threads_writes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/hold_lock.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/hold_repo_lock.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/helpers/worker_probe.mjs +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_account_name_check.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_account_report.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_accounts_dir.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_api_error_body.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_approval.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_ask.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_atlas_fifth_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_atlas_fourth_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_atlas_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_atlas_second_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_atlas_third_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit1_fixes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit2_fixes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_b_counterexamples.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_b_m1_semantics.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_b_n1_depth.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_b_r1_closure.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_v201.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_audit_v23_details.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_auth.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_auth_identity_required.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_bluesky_secret_scrub.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_board_needs_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_board_running.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_bundle.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_charcount.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_cli_entrypoint.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_collect.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_collect_runs.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_collect_sent.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_comparability.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_control_chars_refused.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_conversation_paging.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_count_for.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_doctor.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_doctor_all_permissions.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_doctor_next_step.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_duplicate_front_matter_keys.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_editorial_audit.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_editorial_n3_n4.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_external_acceptance.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_form_spec.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_form_spec_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_forms.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_fresh_install.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_front_matter_injection.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_hypotheses.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_hypothesis_boundaries.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_hypothesis_units.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_impact_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_inbox_granted_scopes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_independent_thread_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_independent_topic_review.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_independent_topic_review_r2.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_inflight.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_jst.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_lint.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_list_projections.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_llm_trial.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_lock.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_m2_independent.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_maintain.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_max_per_run.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_mcp_robustness.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_measured.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_media_accounts.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_media_next_steps.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_media_roundtrip.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_mismatch_diagnostics.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_n5_reply_null_element.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_n6_replies_incomplete_ledger.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_n7_doctor_error_body.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_no_limits.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_observation_provenance.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_preview.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_production_mode.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_queue.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_quiet_hours.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_r2_r4_r5.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_reason_adoption.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_redact.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_redirect_token_leak.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_refresh.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_refresh_destination.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_rejudge_new.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_rejudge_r2_r3.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_replies.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_replies_refresh.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_repo_lock.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_repo_sync.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_reverse_audit.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_case_id_cluster_m2.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_case_id_cluster_r2.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_evidence_account.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_form_spec_and_case_id.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_provenance.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_review_records.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_revoke.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_roundtrip.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_run_missing_env.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_run_record_failclosed.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_runs_collected.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_schedule_multiple.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_schedule_view.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_scopes_source_requested.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_secret_value_redact.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_secrets_grep.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_security_small_fixes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_select.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_send.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_send_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_send_media.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_send_visibility.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_sent_integrity.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_server_json.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_site.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_systemd.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_thread_publish.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_threadrun.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_threadshape.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_thth_root.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_token_exists.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_token_scopes_record.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_token_set.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_advice.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_models.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_shelf_observers.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topic_store.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topics_record_concurrent.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_topics_tool.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_trial_frictions.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_v21b_approved_writes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_value_domains_shown.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_version.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_writeback_rebase.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/tests/test_writeback_validate.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/__init__.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/__main__.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/account_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/account_report.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/adapters/__init__.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/appenv.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/approval.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/ask.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/ask_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/bundle.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/collect.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/doctor.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/forms.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/httpsafe.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/inflight.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/jst.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/lock.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/maintain.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/measured.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/oauth.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/postid.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/queuefile.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/redact.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/replies.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/report.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/retract_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/scopes.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/secrets_fs.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/select.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/sent.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/systemd_gen.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/threadrun.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/threadshape.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/threadthrow.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/topic_advice.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/topic_cli.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/topic_models.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/topic_store.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/topics.py +0 -0
- {thth-2.2.0 → thth-2.3.0}/thth/writeback.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: thth
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
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
|
|
@@ -33,7 +33,7 @@ watchtower(`~/Developer/watchtower`)の隣に同じ流儀で並べる。watc
|
|
|
33
33
|
|
|
34
34
|
## 版
|
|
35
35
|
|
|
36
|
-
**2.0.1**。門を無料で開ける版(2.0.1: 同席送信の採集・セキュリティ監査 2 回の直し)(`pip install`・`thth ask
|
|
36
|
+
**2.0.1**。門を無料で開ける版(2.0.1: 同席送信の採集・セキュリティ監査 2 回の直し)(`pip install`・`thth ask`・台帳を repo の外へ)。範囲と裁定は [docs/設計_v2_泉と門_2026-09-13.md](docs/設計_v2_泉と門_2026-09-13.md) §3・§7、その前の版は [docs/設計_v1.0.0_他人が導入できる版_2026-09-12.md](docs/設計_v1.0.0_他人が導入できる版_2026-09-12.md)、導入は [docs/導入_自分のMetaアプリで動かす.md](docs/導入_自分のMetaアプリで動かす.md)、文書の索引は [docs/README.md](docs/README.md)。
|
|
37
37
|
|
|
38
38
|
`thth/VERSION` は `2.0.1`(版は `thth/VERSION` の 1 か所・`server.json` はテストで一致を強制)。`origin/release` は v2.0.0(`216af9f`)で、**v2.0.1 はまだ配っていない**(配布は masaru の一言)。出口条件の試験は(運用日誌 thth-notes: `記録/試験_LLMに選ばせる_2026-09-13.md`)。
|
|
39
39
|
|
|
@@ -45,7 +45,7 @@ watchtower(`~/Developer/watchtower`)の隣に同じ流儀で並べる。watc
|
|
|
45
45
|
|
|
46
46
|
## いまの状態(2026-09-13)
|
|
47
47
|
|
|
48
|
-
版 **2.
|
|
48
|
+
版 **2.3.0**。全件テスト **2274 件**(`python -m pytest tests/ -q -n auto -p no:cacheprovider`・1 skip・rc=0)。
|
|
49
49
|
|
|
50
50
|
**媒体**: Threads(稼働)・Bluesky・Mastodon(同席用の台帳あり・未稼働)。
|
|
51
51
|
|
|
@@ -74,16 +74,12 @@ timer(systemd・`thth systemd` で生成)で毎時投稿、返信の採集
|
|
|
74
74
|
は `local`。泉のサーバはまだ無い)。原稿本文は渡さないし、答えにも出ない。
|
|
75
75
|
**n が閾値(既定 20)に満たない群は中央値を返さず `cannot_say` に理由を出す**——
|
|
76
76
|
手元の水ではほとんどが `cannot_say` になる。それが正しい答えで、rc は 0。MCP からは `before_you_post`。
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
`$THTH_ROOT/state/share/outbox/<YYYY-MM>.ndjson` に積むだけで、**送り先はまだ無い**(v2-5)。
|
|
80
|
-
積んだ全部は `thth share log` で読める。落ちるのは語・audience・型・件数・時刻帯・
|
|
81
|
-
post_id の**塩つき sha256**(塩は outbox に出ない)。本文・返信本文・返信者の username・
|
|
82
|
-
自分の判断・アカウント名・トークン・repo のパス・生の post_id は落ちない。
|
|
77
|
+
- **読む口(`thth where`・`thth thread`・`thth who`)は何も保存しない**(裁定
|
|
78
|
+
2026-09-16「横断の泉はやめる」)。残るのは絡みの台帳(自分の行為と反応)だけ。
|
|
83
79
|
- **英語の文書**: [README.en.md](README.en.md)・[docs/usage.en.md](docs/usage.en.md)・[llms.txt](llms.txt)。
|
|
84
80
|
- **skill**: `skills/thth/SKILL.md`(wheel にも入る)。
|
|
85
81
|
|
|
86
|
-
- **動くもの**(`thth --help` の全
|
|
82
|
+
- **動くもの**(`thth --help` の全 34 サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`who`・`retract`・`location`。
|
|
87
83
|
- **最初の本番投稿の記録**: 2026-09-09、@aoking に疎通確認を 1 本(`17916074118445631`)。
|
|
88
84
|
- **未着手**: X・Facebook ページ・Instagram の各アダプタ。トピック検索の権限(tester には降りない)。泉のサーバ(v2-5)。
|
|
89
85
|
- **権限の制約**: tester に降りる scope は 5 つ。削除はできない。
|
|
@@ -9,7 +9,7 @@ watchtower(`~/Developer/watchtower`)の隣に同じ流儀で並べる。watc
|
|
|
9
9
|
|
|
10
10
|
## 版
|
|
11
11
|
|
|
12
|
-
**2.0.1**。門を無料で開ける版(2.0.1: 同席送信の採集・セキュリティ監査 2 回の直し)(`pip install`・`thth ask
|
|
12
|
+
**2.0.1**。門を無料で開ける版(2.0.1: 同席送信の採集・セキュリティ監査 2 回の直し)(`pip install`・`thth ask`・台帳を repo の外へ)。範囲と裁定は [docs/設計_v2_泉と門_2026-09-13.md](docs/設計_v2_泉と門_2026-09-13.md) §3・§7、その前の版は [docs/設計_v1.0.0_他人が導入できる版_2026-09-12.md](docs/設計_v1.0.0_他人が導入できる版_2026-09-12.md)、導入は [docs/導入_自分のMetaアプリで動かす.md](docs/導入_自分のMetaアプリで動かす.md)、文書の索引は [docs/README.md](docs/README.md)。
|
|
13
13
|
|
|
14
14
|
`thth/VERSION` は `2.0.1`(版は `thth/VERSION` の 1 か所・`server.json` はテストで一致を強制)。`origin/release` は v2.0.0(`216af9f`)で、**v2.0.1 はまだ配っていない**(配布は masaru の一言)。出口条件の試験は(運用日誌 thth-notes: `記録/試験_LLMに選ばせる_2026-09-13.md`)。
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ watchtower(`~/Developer/watchtower`)の隣に同じ流儀で並べる。watc
|
|
|
21
21
|
|
|
22
22
|
## いまの状態(2026-09-13)
|
|
23
23
|
|
|
24
|
-
版 **2.
|
|
24
|
+
版 **2.3.0**。全件テスト **2274 件**(`python -m pytest tests/ -q -n auto -p no:cacheprovider`・1 skip・rc=0)。
|
|
25
25
|
|
|
26
26
|
**媒体**: Threads(稼働)・Bluesky・Mastodon(同席用の台帳あり・未稼働)。
|
|
27
27
|
|
|
@@ -50,16 +50,12 @@ timer(systemd・`thth systemd` で生成)で毎時投稿、返信の採集
|
|
|
50
50
|
は `local`。泉のサーバはまだ無い)。原稿本文は渡さないし、答えにも出ない。
|
|
51
51
|
**n が閾値(既定 20)に満たない群は中央値を返さず `cannot_say` に理由を出す**——
|
|
52
52
|
手元の水ではほとんどが `cannot_say` になる。それが正しい答えで、rc は 0。MCP からは `before_you_post`。
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
`$THTH_ROOT/state/share/outbox/<YYYY-MM>.ndjson` に積むだけで、**送り先はまだ無い**(v2-5)。
|
|
56
|
-
積んだ全部は `thth share log` で読める。落ちるのは語・audience・型・件数・時刻帯・
|
|
57
|
-
post_id の**塩つき sha256**(塩は outbox に出ない)。本文・返信本文・返信者の username・
|
|
58
|
-
自分の判断・アカウント名・トークン・repo のパス・生の post_id は落ちない。
|
|
53
|
+
- **読む口(`thth where`・`thth thread`・`thth who`)は何も保存しない**(裁定
|
|
54
|
+
2026-09-16「横断の泉はやめる」)。残るのは絡みの台帳(自分の行為と反応)だけ。
|
|
59
55
|
- **英語の文書**: [README.en.md](README.en.md)・[docs/usage.en.md](docs/usage.en.md)・[llms.txt](llms.txt)。
|
|
60
56
|
- **skill**: `skills/thth/SKILL.md`(wheel にも入る)。
|
|
61
57
|
|
|
62
|
-
- **動くもの**(`thth --help` の全
|
|
58
|
+
- **動くもの**(`thth --help` の全 34 サブコマンド): `lint`・`preview`・`approve`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`who`・`retract`・`location`。
|
|
63
59
|
- **最初の本番投稿の記録**: 2026-09-09、@aoking に疎通確認を 1 本(`17916074118445631`)。
|
|
64
60
|
- **未着手**: X・Facebook ページ・Instagram の各アダプタ。トピック検索の権限(tester には降りない)。泉のサーバ(v2-5)。
|
|
65
61
|
- **権限の制約**: tester に降りる scope は 5 つ。削除はできない。
|
|
@@ -139,6 +139,118 @@ TOOLS = [
|
|
|
139
139
|
"required": ["account", "topic"],
|
|
140
140
|
},
|
|
141
141
|
},
|
|
142
|
+
{
|
|
143
|
+
# **名前と説明文がそのまま売り文句**(設計「自分の泉」§2.2)。
|
|
144
|
+
# 実装が 1 語でも足したら設計書でなく実装を戻す(§2 の頭書きそのまま)。
|
|
145
|
+
"name": "after_you_posted",
|
|
146
|
+
# **設計「自分の泉」§2.2 の文言そのまま。**
|
|
147
|
+
"description": (
|
|
148
|
+
"出したあとに呼ぶ。この語・この型・この枝で、自分の投稿と返信が"
|
|
149
|
+
"どう受け取られたかを、件数と期間つきで返す"
|
|
150
|
+
),
|
|
151
|
+
"inputSchema": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"account": {"type": "string", "description": "account 名"},
|
|
155
|
+
"topic": {"type": "string", "description": "語(トピック)"},
|
|
156
|
+
"kind": {"type": "string", "description": "型(行動・年度付き 等)"},
|
|
157
|
+
"hour_band": {"type": "string",
|
|
158
|
+
"description": "時刻帯(朝・昼・夕・深夜)で絞る"},
|
|
159
|
+
"reply_to": {"type": "string",
|
|
160
|
+
"description": "この post_id への返信だけに絞る"},
|
|
161
|
+
"author_key": {"type": "string",
|
|
162
|
+
"description": "この仮名(16 進 16 桁)への返信だけに絞る"},
|
|
163
|
+
"window_days": {"type": "integer", "description": "直近何日(既定 30)"},
|
|
164
|
+
"min_n": {"type": "integer",
|
|
165
|
+
"description": "中央値を返す下限(既定 5)"},
|
|
166
|
+
},
|
|
167
|
+
"required": ["account"],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
# **名前と説明文がそのまま売り文句**(設計「自分の泉」§2.1)。
|
|
172
|
+
# 実装が 1 語でも足したら設計書でなく実装を戻す(§2 の頭書きそのまま)。
|
|
173
|
+
"name": "thread_read",
|
|
174
|
+
# **設計「自分の泉」§2.1 の文言そのまま。**
|
|
175
|
+
"description": (
|
|
176
|
+
"返信を書く前に呼ぶ。この投稿の枝を、誰が・いつ・何を・誰に向けて"
|
|
177
|
+
"言ったかの順で返す。何も保存しない"
|
|
178
|
+
),
|
|
179
|
+
"inputSchema": {
|
|
180
|
+
"type": "object",
|
|
181
|
+
"properties": {
|
|
182
|
+
"account": {"type": "string", "description": "account 名"},
|
|
183
|
+
"post_id": {"type": "string", "description": "枝の根の post_id"},
|
|
184
|
+
"since": {"type": "string", "description": "この時刻以降だけ"},
|
|
185
|
+
"max_messages": {"type": "integer",
|
|
186
|
+
"description": "読む上限(既定 200・上限 1000)"},
|
|
187
|
+
},
|
|
188
|
+
"required": ["account", "post_id"],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
# **名前と説明文がそのまま売り文句**(設計「自分の泉」§2.3)。
|
|
193
|
+
# 実装が 1 語でも足したら設計書でなく実装を戻す(§2 の頭書きそのまま)。
|
|
194
|
+
"name": "where_to_appear",
|
|
195
|
+
# **設計「自分の泉」§2.3 の文言そのまま。**
|
|
196
|
+
"description": (
|
|
197
|
+
"絡みに行く先を選ぶ前に呼ぶ。検索の一覧に、自分の履歴(この語・"
|
|
198
|
+
"この相手で何が起きたか)を重ねて返す。選ぶのは呼ぶ側"
|
|
199
|
+
),
|
|
200
|
+
"inputSchema": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"account": {"type": "string",
|
|
204
|
+
"description": "account 名(project の代わり)"},
|
|
205
|
+
"project": {"type": "string",
|
|
206
|
+
"description": "この project の account 全部"
|
|
207
|
+
"(account の代わり)"},
|
|
208
|
+
"words": {"type": "array", "items": {"type": "string"},
|
|
209
|
+
"description": "検索の語(1〜5 個)"},
|
|
210
|
+
"recent": {"type": "boolean",
|
|
211
|
+
"description": "TOP でなく RECENT(新しい順)で検索する"},
|
|
212
|
+
"limit": {"type": "integer",
|
|
213
|
+
"description": "1 account・1 語あたりの上限(既定 25)"},
|
|
214
|
+
},
|
|
215
|
+
# **`account` か `project` のどちらか必須**(両方無ければ
|
|
216
|
+
# `validate_arguments()` が `-32602`)。`required` は AND
|
|
217
|
+
# (全部要る)の意味しか持てないので、ここには入れない——OR の
|
|
218
|
+
# 検査は `validate_arguments()` の `where_to_appear` 専用の分岐で行う。
|
|
219
|
+
"required": ["words"],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
# **名前と説明文がそのまま売り文句**(設計「自分の泉」§2.4)。
|
|
224
|
+
# 実装が 1 語でも足したら設計書でなく実装を戻す(§2 の頭書きそのまま)。
|
|
225
|
+
"name": "who_is_this",
|
|
226
|
+
# **設計「自分の泉」§2.4 の文言そのまま。**
|
|
227
|
+
"description": (
|
|
228
|
+
"返信する相手を確かめる。この仮名と自分のアカウントの接触の"
|
|
229
|
+
"回数・時期・反応を返す。発言の内容は持たない"
|
|
230
|
+
),
|
|
231
|
+
"inputSchema": {
|
|
232
|
+
"type": "object",
|
|
233
|
+
"properties": {
|
|
234
|
+
"account": {"type": "string",
|
|
235
|
+
"description": "account 名(project の代わり)"},
|
|
236
|
+
"project": {"type": "string",
|
|
237
|
+
"description": "この project の account 全部"
|
|
238
|
+
"(account の代わり)"},
|
|
239
|
+
"author_key": {"type": "string",
|
|
240
|
+
"description": "仮名(16 進 16 桁・username の代わり)"},
|
|
241
|
+
"username": {"type": "string",
|
|
242
|
+
"description": "@ 無しでも可。その場で author_key に"
|
|
243
|
+
"写す(保存しない・author_key の代わり)"},
|
|
244
|
+
"profile": {"type": "boolean",
|
|
245
|
+
"description": "その場で公開プロフィールを引く"
|
|
246
|
+
"(Threads だけ・保存しない・既定 false)"},
|
|
247
|
+
},
|
|
248
|
+
# **`account`/`project` と `author_key`/`username`、どちらも
|
|
249
|
+
# 「片方だけ必須」の OR**(`where_to_appear` と同じ理由で
|
|
250
|
+
# `required` には入れない——`validate_arguments()` の
|
|
251
|
+
# `who_is_this` 専用の分岐で見る)。
|
|
252
|
+
},
|
|
253
|
+
},
|
|
142
254
|
]
|
|
143
255
|
|
|
144
256
|
|
|
@@ -168,6 +280,10 @@ _TYPES = {
|
|
|
168
280
|
"boolean": ((bool,), "真偽値"),
|
|
169
281
|
"integer": ((int,), "整数"),
|
|
170
282
|
"number": ((int, float), "数"),
|
|
283
|
+
# `where_to_appear` の `words`(T2-3)で初めて使う型。**配列だけを通す**
|
|
284
|
+
# ——足しておかないと `_TYPES.get(...)` の既定(`(object,)`)に落ちて、
|
|
285
|
+
# 文字列 1 個を渡しても素通りしてしまう。
|
|
286
|
+
"array": ((list,), "配列"),
|
|
171
287
|
}
|
|
172
288
|
|
|
173
289
|
|
|
@@ -266,8 +382,35 @@ def validate_arguments(name: str, arguments) -> dict:
|
|
|
266
382
|
raise ToolInputError(
|
|
267
383
|
f"{name}: {key} が `-` で始まっています({value!r})。"
|
|
268
384
|
f"CLI の旗と区別できないので受け取りません")
|
|
385
|
+
if (spec.get("type") == "array"
|
|
386
|
+
and (spec.get("items") or {}).get("type") == "string"):
|
|
387
|
+
# **`words` の各要素も同じ理由で縛る**(監査 2026-09-14・P3-2 と同じ筋・
|
|
388
|
+
# T2-3)。`call_tool()` は要素を argv にそのまま並べるので、ここで
|
|
389
|
+
# 文字列でないもの・`-` で始まるものを通すと `thth where` の別の旗と
|
|
390
|
+
# 区別できなくなる。
|
|
391
|
+
for item in value:
|
|
392
|
+
if not isinstance(item, str):
|
|
393
|
+
raise ToolInputError(
|
|
394
|
+
f"{name}: {key} の要素は文字列です"
|
|
395
|
+
f"(受け取った: {type(item).__name__})")
|
|
396
|
+
if item.startswith("-"):
|
|
397
|
+
raise ToolInputError(
|
|
398
|
+
f"{name}: {key} の要素が `-` で始まっています({item!r})。"
|
|
399
|
+
f"CLI の旗と区別できないので受け取りません")
|
|
269
400
|
if key == "file":
|
|
270
401
|
check_file_argument(name, value)
|
|
402
|
+
if name in ("where_to_appear", "who_is_this") and not arguments.get("account") \
|
|
403
|
+
and not arguments.get("project"):
|
|
404
|
+
# **`account` か `project` のどちらか必須**(`required` は AND の意味しか
|
|
405
|
+
# 持てないので、ここで OR を見る・T2-3 発注書・T3-3 も同じ形)。
|
|
406
|
+
raise ToolInputError(
|
|
407
|
+
f"{name}: account か project のどちらかが要ります")
|
|
408
|
+
if name == "who_is_this" and not arguments.get("author_key") \
|
|
409
|
+
and not arguments.get("username"):
|
|
410
|
+
# **`author_key` か `username` のどちらか必須**(同じ理由で OR を
|
|
411
|
+
# ここで見る・T3-3 発注書)。
|
|
412
|
+
raise ToolInputError(
|
|
413
|
+
f"{name}: author_key か username のどちらかが要ります")
|
|
271
414
|
return arguments
|
|
272
415
|
|
|
273
416
|
|
|
@@ -342,15 +485,86 @@ def call_tool(name: str, arguments: dict | None) -> dict:
|
|
|
342
485
|
args.append("--json")
|
|
343
486
|
proc = run_cli(args)
|
|
344
487
|
text = proc.stdout
|
|
488
|
+
elif name == "after_you_posted":
|
|
489
|
+
# **`before_you_post` と同じ型**(発注 T0-2): CLI を `--json` で呼ぶだけ。
|
|
490
|
+
args = ["after", arguments["account"]]
|
|
491
|
+
if arguments.get("topic"):
|
|
492
|
+
args += ["--topic", arguments["topic"]]
|
|
493
|
+
if arguments.get("kind"):
|
|
494
|
+
args += ["--kind", arguments["kind"]]
|
|
495
|
+
if arguments.get("hour_band"):
|
|
496
|
+
args += ["--hour-band", arguments["hour_band"]]
|
|
497
|
+
if arguments.get("reply_to"):
|
|
498
|
+
args += ["--reply-to", arguments["reply_to"]]
|
|
499
|
+
if arguments.get("author_key"):
|
|
500
|
+
args += ["--author-key", arguments["author_key"]]
|
|
501
|
+
if arguments.get("window_days") is not None:
|
|
502
|
+
args += ["--window-days", str(arguments["window_days"])]
|
|
503
|
+
if arguments.get("min_n") is not None:
|
|
504
|
+
args += ["--min-n", str(arguments["min_n"])]
|
|
505
|
+
args.append("--json")
|
|
506
|
+
proc = run_cli(args)
|
|
507
|
+
text = proc.stdout
|
|
508
|
+
elif name == "thread_read":
|
|
509
|
+
# **`after_you_posted` と同じ型**: CLI(`thth thread`)を `--json` で
|
|
510
|
+
# 呼ぶだけ(設計「自分の泉」§2.1・T1-3)。
|
|
511
|
+
args = ["thread", arguments["account"], arguments["post_id"]]
|
|
512
|
+
if arguments.get("since"):
|
|
513
|
+
args += ["--since", arguments["since"]]
|
|
514
|
+
if arguments.get("max_messages") is not None:
|
|
515
|
+
args += ["--max-messages", str(arguments["max_messages"])]
|
|
516
|
+
args.append("--json")
|
|
517
|
+
proc = run_cli(args)
|
|
518
|
+
text = proc.stdout
|
|
519
|
+
elif name == "where_to_appear":
|
|
520
|
+
# **`thread_read` と同じ型**: CLI(`thth where`)を `--json` で呼ぶ
|
|
521
|
+
# だけ(設計「自分の泉」§2.3・T2-3)。`account`/`project` のどちらか
|
|
522
|
+
# 必須は `validate_arguments()` が先に見ているので、ここでは
|
|
523
|
+
# `project` を優先するだけでよい。
|
|
524
|
+
args = ["where"]
|
|
525
|
+
if arguments.get("project"):
|
|
526
|
+
args += ["--project", arguments["project"]]
|
|
527
|
+
else:
|
|
528
|
+
args.append(arguments["account"])
|
|
529
|
+
args += list(arguments.get("words") or [])
|
|
530
|
+
if arguments.get("recent"):
|
|
531
|
+
args.append("--recent")
|
|
532
|
+
if arguments.get("limit") is not None:
|
|
533
|
+
args += ["--limit", str(arguments["limit"])]
|
|
534
|
+
args.append("--json")
|
|
535
|
+
proc = run_cli(args)
|
|
536
|
+
text = proc.stdout
|
|
537
|
+
elif name == "who_is_this":
|
|
538
|
+
# **`where_to_appear` と同じ型**: CLI(`thth who`)を `--json` で呼ぶ
|
|
539
|
+
# だけ(設計「自分の泉」§2.4・T3-3)。`account`/`project` と
|
|
540
|
+
# `author_key`/`username` のどちらかずつ必須は `validate_arguments()`
|
|
541
|
+
# が先に見ているので、ここでは組み立てるだけでよい。
|
|
542
|
+
args = ["who"]
|
|
543
|
+
if arguments.get("project"):
|
|
544
|
+
args += ["--project", arguments["project"]]
|
|
545
|
+
else:
|
|
546
|
+
args.append(arguments["account"])
|
|
547
|
+
if arguments.get("author_key"):
|
|
548
|
+
args.append(arguments["author_key"])
|
|
549
|
+
else:
|
|
550
|
+
args.append("@" + arguments["username"])
|
|
551
|
+
if arguments.get("profile"):
|
|
552
|
+
args.append("--profile")
|
|
553
|
+
args.append("--json")
|
|
554
|
+
proc = run_cli(args)
|
|
555
|
+
text = proc.stdout
|
|
345
556
|
else:
|
|
346
557
|
return {"content": [{"type": "text", "text": f"unknown tool: {name}"}], "isError": True}
|
|
347
558
|
|
|
348
|
-
if name.startswith("thth_topic_") or name
|
|
559
|
+
if name.startswith("thth_topic_") or name in (
|
|
560
|
+
"before_you_post", "after_you_posted", "thread_read", "where_to_appear",
|
|
561
|
+
"who_is_this"):
|
|
349
562
|
# **新しい道具は exit 1 も isError**(設計 §7)。lint の exit 1(検査結果)
|
|
350
563
|
# とは意味が違う——こちらは stale_context・不正な候補比較で、
|
|
351
564
|
# **そのまま使ってはいけない**応答。既存の扱いは変えない。
|
|
352
|
-
# `before_you_post` も同じ(設計 v2 §1):
|
|
353
|
-
#
|
|
565
|
+
# `before_you_post`/`after_you_posted` も同じ(設計 v2 §1・「自分の泉」§5):
|
|
566
|
+
# exit 1 は台帳が無い、2 は問いが受け取れない。**`cannot_say` だらけの
|
|
567
|
+
# 答えは exit 0 で、error ではない。**
|
|
354
568
|
is_error = proc.returncode != 0
|
|
355
569
|
else:
|
|
356
570
|
is_error = proc.returncode not in (0, 1) # lint は 1 も正常な「検査結果」
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: thth
|
|
3
|
+
description: 投稿する前・返信を書く前・出したあと・絡みに行く先を選ぶときに呼ぶ道具。Threads・Bluesky・Mastodon への下書きを人の承認を通してから出し、枝を読み、相手を知り、伸びを測る。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# THTH — 投稿する前に呼ぶ道具
|
|
7
|
+
|
|
8
|
+
## 何を保証するか
|
|
9
|
+
|
|
10
|
+
- **人が承認していない本文は 1 文字も出ない。** 承認は 2 段(見せる → digest を渡す)。
|
|
11
|
+
digest が違えば拒否する。**「見せた本文」と「出す本文」が同じであることを機械が確かめる。**
|
|
12
|
+
- **`--production` を付けるまで出ない。** 付けない実行は、投げるはずの本文と digest を
|
|
13
|
+
表示して終わる。
|
|
14
|
+
- **記録は利用者の git に残る。** post_id・承認者・承認時刻・返信・実測は、あなたの repo の
|
|
15
|
+
commit として残る。THTH のサーバには何も無い。
|
|
16
|
+
- **数値には分母が付く。** 件数・期間・揃えた条件が無い数字は返さない。取れていない刻みは
|
|
17
|
+
`null` であって `0` ではない。
|
|
18
|
+
- **黙って間違えない。** 拒むときは理由と次の一手を言って非ゼロで終わる(loud reject)。
|
|
19
|
+
|
|
20
|
+
## 何を拒むか
|
|
21
|
+
|
|
22
|
+
- **`--confirm` の無い本番。** digest の食い違う本番。承認後に本文が変わった下書き
|
|
23
|
+
(`approval_stale`)。
|
|
24
|
+
- **同期を確認していない commit の本文。** ディスクに置いただけのファイルは選ばれない。
|
|
25
|
+
- **静かな時間帯・最短間隔に反する投稿。**
|
|
26
|
+
- **語(トピック)の未確認。** 承認の一段目が「未確認です」と言う。
|
|
27
|
+
|
|
28
|
+
## 何を絶対にしないか
|
|
29
|
+
|
|
30
|
+
- **何を書くかを決めない。** 文体・頻度・時刻・語の選び方はあなたのプロジェクトのもの。
|
|
31
|
+
渡された本文を**整形も切り詰めもせず**そのまま出す。
|
|
32
|
+
- **読む口は何も保存しない。** `thread_read`・`where_to_appear`・`who_is_this` はどれも、
|
|
33
|
+
読んで見せるだけで**台帳に 1 バイトも書かない**。残るのは**自分の行為と反応**
|
|
34
|
+
(絡みの台帳)だけで、**相手の本文・相手の名前・あなたの判断は台帳に入らない**。
|
|
35
|
+
- **人の代わりに承認しない。** あなた(エージェント)は下書きと digest を人に見せ、
|
|
36
|
+
人が `--confirm` を打つ。
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 使う順番——場面で
|
|
41
|
+
|
|
42
|
+
### 1. 探す——どこに絡みに行くか
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
thth where <account> <語…> # 検索の一覧に自分の履歴を重ねて返す
|
|
46
|
+
thth where --project <P> <語…> # project 単位で全媒体を一度に
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
MCP `where_to_appear`。**順位は無い**——材料を並べるだけで、選ぶのは LLM。
|
|
50
|
+
**残すもの: なし**(この口自身は何も書かない。材料は `after_you_posted` と
|
|
51
|
+
絡みの台帳から来ている)。
|
|
52
|
+
**呼ばなくてよいとき**: 返す先がもう決まっている・自分の投稿への返信。
|
|
53
|
+
|
|
54
|
+
### 2. 読む——枝をその場で
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
thth thread <account> <post_id>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
MCP `thread_read`。枝の会話を**生で**読み、誰がどんな立場かをその場で判断する。
|
|
61
|
+
**`already_replied` を見落とさない**——もうこの枝に返しているかがここに乗る。
|
|
62
|
+
**残すもの: なし**(読んで捨てる。runs には件数だけ)。
|
|
63
|
+
**呼ばなくてよいとき**: 自分の根の枝は `thth threads` の形で足りるとき。
|
|
64
|
+
|
|
65
|
+
### 3. 相手を知る——この仮名と何度
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
thth who <account> <author_key>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
MCP `who_is_this`。この仮名と自分のアカウントが何度・いつ・どんな反応だったか
|
|
72
|
+
だけを返す。**人物像ではない**——発言の内容は持たない。
|
|
73
|
+
**残すもの: なし**(絡みの台帳・返信の台帳から導くだけで、この口自体は書かない)。
|
|
74
|
+
|
|
75
|
+
### 4. 書く——下書きに宛先を乗せる
|
|
76
|
+
|
|
77
|
+
下書きの front-matter に:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
reply_to: <post_id>
|
|
81
|
+
reply_to_author_key: <一覧の --json の author_key をそのまま写す>
|
|
82
|
+
found_by: where_to_appear|manual|mention
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**残すもの**: この 3 つの欄(下書きファイルそのもの。承認まではあなたの repo の
|
|
86
|
+
untracked/コミット前のファイル)。語を選ぶときだけ `before_you_post`
|
|
87
|
+
(原稿本文は渡さない・件数と期間つきで返す)。
|
|
88
|
+
|
|
89
|
+
### 5. 承認——二段(そのまま)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
thth lint <ファイル…> # front-matter と字数の検査
|
|
93
|
+
thth preview <ファイル> # 実際に投げる本文そのもの
|
|
94
|
+
thth approve <ファイル or ディレクトリ> # 一段目: 本文と digest を見せる
|
|
95
|
+
thth approve <同じ> --confirm <digest> --by "<承認した人>" # 二段目: 承認して commit
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**一段目は非ゼロで終わる。** それは失敗ではなく「まだ承認していない」。
|
|
99
|
+
**`--by` に人の名前を書く。** 承認したのは人であって、あなたではない。
|
|
100
|
+
**残すもの**: post_id・承認者・承認時刻(あなたの repo の commit)。
|
|
101
|
+
|
|
102
|
+
### 6. 測る——出したあとの反応
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
thth after <account> [--reply-to <post_id>] [--topic …]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
MCP `after_you_posted`。**24h の刻みが無ければ `null`**(0 と混ぜない・
|
|
109
|
+
`covered: false` を付ける)。`one_thing_to_change` は 1 個か `null`。
|
|
110
|
+
**残すもの: なし**(この口は読むだけ。絡みの台帳は**公開の瞬間**に 1 行書かれる——
|
|
111
|
+
自分の行為と反応だけで、相手の本文・名前・自分の判断は入らない)。
|
|
112
|
+
**媒体をまたぐ数は無い**——project 単位で並べるだけで、足さない・割らない・
|
|
113
|
+
順位も付けない。
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 詰まったら
|
|
118
|
+
|
|
119
|
+
- `thth --help` / `thth <subcommand> --help` が正本。
|
|
120
|
+
- `thth doctor <account>` が「いま投稿できる状態か」を最初から最後まで言う。
|
|
121
|
+
- 使い方の全文: `docs/使い方_プロジェクトのセッション向け_2026-09-09.md`。
|
|
@@ -95,9 +95,12 @@ def test_TB0_capabilitiesは実体を作らずに引ける():
|
|
|
95
95
|
# `keyword_search`・`mentions`・`profile_lookup`・`inbox` は v2.1-A(設計 v2
|
|
96
96
|
# §4.3・2026-09-14)で足した語。Threads の 11 権限を使う読み取りの口 3 つと、
|
|
97
97
|
# 言及を `inbox` に流す配管(v2-3 の芽がそのまま受け皿)。
|
|
98
|
+
# `thread_read` は設計「自分の泉」T1-1(2026-09-16)で足した語。
|
|
99
|
+
# `fetch_post()` が根を 1 件引ける(3 媒体とも持つ)。
|
|
98
100
|
assert threads_mod.ThreadsAdapter.capabilities() == {
|
|
99
101
|
"topic", "link_preview", "views", "quota", "refresh", "recent_posts",
|
|
100
|
-
"account_insights", "keyword_search", "mentions", "profile_lookup", "inbox"
|
|
102
|
+
"account_insights", "keyword_search", "mentions", "profile_lookup", "inbox",
|
|
103
|
+
"thread_read"}
|
|
101
104
|
|
|
102
105
|
|
|
103
106
|
def test_F3_metrics_ofは新しい形だけを受ける():
|