threadkeeper 0.17.1__tar.gz → 0.17.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/PKG-INFO +7 -2
  2. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/README.md +6 -1
  3. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/pyproject.toml +1 -1
  4. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_evolve_applier.py +64 -0
  5. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/evolve_applier.py +58 -2
  6. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/PKG-INFO +7 -2
  7. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/LICENSE +0 -0
  8. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/setup.cfg +0 -0
  9. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_adapters.py +0 -0
  10. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_agent_status.py +0 -0
  11. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_auto_update.py +0 -0
  12. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_backup.py +0 -0
  13. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_brief_footprint.py +0 -0
  14. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_brief_sections.py +0 -0
  15. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_candidate_reviewer.py +0 -0
  16. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_concepts.py +0 -0
  17. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_config_settings.py +0 -0
  18. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_config_watcher.py +0 -0
  19. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_core_memory.py +0 -0
  20. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_curator.py +0 -0
  21. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_daemon_host_config.py +0 -0
  22. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_daemon_host_integration.py +0 -0
  23. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_daemon_liveness.py +0 -0
  24. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_daemon_state.py +0 -0
  25. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dashboard.py +0 -0
  26. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_db_compact.py +0 -0
  27. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_db_contention.py +0 -0
  28. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_db_migration_fts.py +0 -0
  29. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_db_runtime.py +0 -0
  30. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_db_schema.py +0 -0
  31. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_delegated_search.py +0 -0
  32. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic.py +0 -0
  33. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_feed_tools.py +0 -0
  34. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_miner.py +0 -0
  35. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_observation_resolve.py +0 -0
  36. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_recompute.py +0 -0
  37. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_tier.py +0 -0
  38. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialectic_validator.py +0 -0
  39. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_dialog_fts_external.py +0 -0
  40. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_egress_policy.py +0 -0
  41. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_embed_routing.py +0 -0
  42. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_embedding_generation.py +0 -0
  43. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_embedding_model_revision.py +0 -0
  44. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_embedding_storage_dedup.py +0 -0
  45. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_error_paths.py +0 -0
  46. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_eval_harness.py +0 -0
  47. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_evolve_apply_2.py +0 -0
  48. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_evolve_apply_3.py +0 -0
  49. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_evolve_daemon.py +0 -0
  50. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_extract_daemon.py +0 -0
  51. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_extract_dedup.py +0 -0
  52. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_forget.py +0 -0
  53. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_github_budget.py +0 -0
  54. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_github_safety.py +0 -0
  55. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_helpers.py +0 -0
  56. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_host_embed.py +0 -0
  57. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_host_env.py +0 -0
  58. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_host_main.py +0 -0
  59. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_host_wedged.py +0 -0
  60. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_hybrid_retrieval.py +0 -0
  61. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_i18n_multilang.py +0 -0
  62. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_identity.py +0 -0
  63. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_ingest_cursor.py +0 -0
  64. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_ingest_denylist.py +0 -0
  65. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_ingest_secret_redaction.py +0 -0
  66. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_ingest_status.py +0 -0
  67. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_ingest_transactions.py +0 -0
  68. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_lessons.py +0 -0
  69. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_mcp_resources_prompts.py +0 -0
  70. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_memory_eval.py +0 -0
  71. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_memory_guard.py +0 -0
  72. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_memory_guard_host.py +0 -0
  73. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_menubar_app.py +0 -0
  74. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_missed_spawns.py +0 -0
  75. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_model_catalog.py +0 -0
  76. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_notify_daemon.py +0 -0
  77. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_nudges.py +0 -0
  78. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_onnx_embeddings.py +0 -0
  79. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_panel.py +0 -0
  80. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_permissions.py +0 -0
  81. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_pickup.py +0 -0
  82. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_probe_daemon.py +0 -0
  83. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_process_health.py +0 -0
  84. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_release_workflows.py +0 -0
  85. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_retention.py +0 -0
  86. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_review_prompts.py +0 -0
  87. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_search_fts_punctuation.py +0 -0
  88. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_session_read_purity.py +0 -0
  89. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_shadow_review.py +0 -0
  90. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_single_flight_prompt_prefixes.py +0 -0
  91. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_hint.py +0 -0
  92. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_passive_tier.py +0 -0
  93. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_tier.py +0 -0
  94. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_updater.py +0 -0
  95. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_use_parser.py +0 -0
  96. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skill_watcher.py +0 -0
  97. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_skills.py +0 -0
  98. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_budget.py +0 -0
  99. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_codex_stdin.py +0 -0
  100. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_config.py +0 -0
  101. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_hint.py +0 -0
  102. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_permission_gate.py +0 -0
  103. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_reap.py +0 -0
  104. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_slim.py +0 -0
  105. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_watchdog.py +0 -0
  106. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_spawn_wrap.py +0 -0
  107. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_capture.py +0 -0
  108. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_identity.py +0 -0
  109. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_migrate.py +0 -0
  110. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_protocol.py +0 -0
  111. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_reset_node.py +0 -0
  112. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_sync_transport.py +0 -0
  113. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_task_retention.py +0 -0
  114. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_task_spool.py +0 -0
  115. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_thin_session.py +0 -0
  116. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_thread_janitor.py +0 -0
  117. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_threads.py +0 -0
  118. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_tool_annotations.py +0 -0
  119. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_tools_smoke.py +0 -0
  120. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_validate_threads.py +0 -0
  121. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_vec_search.py +0 -0
  122. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/tests/test_verify_ingest.py +0 -0
  123. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/__init__.py +0 -0
  124. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/_mcp.py +0 -0
  125. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/_setup.py +0 -0
  126. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/_spawn_wrap.py +0 -0
  127. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/__init__.py +0 -0
  128. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/_hook_helpers.py +0 -0
  129. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/antigravity.py +0 -0
  130. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/base.py +0 -0
  131. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/claude_code.py +0 -0
  132. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/claude_desktop.py +0 -0
  133. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/codex.py +0 -0
  134. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/copilot.py +0 -0
  135. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/adapters/vscode.py +0 -0
  136. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/agent_metadata.py +0 -0
  137. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/agent_status.py +0 -0
  138. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/assets/macos-agent-status/Info.plist +0 -0
  139. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/assets/macos-agent-status/README.md +0 -0
  140. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/assets/macos-agent-status/ThreadKeeperAgentStatus.swift +0 -0
  141. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/assets/macos-agent-status/build.sh +0 -0
  142. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/assets/macos-agent-status/install.sh +0 -0
  143. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/auto_update.py +0 -0
  144. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/backup.py +0 -0
  145. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/brief.py +0 -0
  146. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/candidate_reviewer.py +0 -0
  147. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/config.py +0 -0
  148. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/config_io.py +0 -0
  149. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/config_watcher.py +0 -0
  150. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/curator.py +0 -0
  151. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/curator_snapshots.py +0 -0
  152. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/daemon_liveness.py +0 -0
  153. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/daemon_state.py +0 -0
  154. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/daemon_supervisor.py +0 -0
  155. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/db.py +0 -0
  156. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/dialectic_miner.py +0 -0
  157. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/dialectic_validator.py +0 -0
  158. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/egress.py +0 -0
  159. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/elicitation.py +0 -0
  160. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/embeddings.py +0 -0
  161. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/eval/__init__.py +0 -0
  162. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/eval/__main__.py +0 -0
  163. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/eval/harness.py +0 -0
  164. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/evolve_daemon.py +0 -0
  165. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/extract_daemon.py +0 -0
  166. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/forget.py +0 -0
  167. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/github_budget.py +0 -0
  168. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/github_safety.py +0 -0
  169. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/harvest.py +0 -0
  170. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/helpers.py +0 -0
  171. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/host.py +0 -0
  172. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/host_embed.py +0 -0
  173. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/i18n.py +0 -0
  174. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/identity.py +0 -0
  175. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/ingest.py +0 -0
  176. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/lessons.py +0 -0
  177. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/memory_guard.py +0 -0
  178. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/menubar_app.py +0 -0
  179. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/migrate_embeddings.py +0 -0
  180. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/model_catalog.py +0 -0
  181. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/notify.py +0 -0
  182. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/nudges.py +0 -0
  183. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/permissions.py +0 -0
  184. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/probe_daemon.py +0 -0
  185. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/process_health.py +0 -0
  186. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/retention.py +0 -0
  187. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/retrieval.py +0 -0
  188. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/review_prompts.py +0 -0
  189. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/search_proxy.py +0 -0
  190. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/server.py +0 -0
  191. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/shadow_review.py +0 -0
  192. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/skill_audit.py +0 -0
  193. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/skill_updater.py +0 -0
  194. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/skill_watcher.py +0 -0
  195. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/spawn_budget.py +0 -0
  196. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/spawn_config.py +0 -0
  197. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/__init__.py +0 -0
  198. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/capture.py +0 -0
  199. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/daemon.py +0 -0
  200. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/identity.py +0 -0
  201. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/migrate.py +0 -0
  202. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/protocol.py +0 -0
  203. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/reset_node.py +0 -0
  204. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/sync/server.py +0 -0
  205. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/task_spool.py +0 -0
  206. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/thread_janitor.py +0 -0
  207. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tool_schemas.py +0 -0
  208. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/__init__.py +0 -0
  209. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/agent_status.py +0 -0
  210. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/candidate_reviewer.py +0 -0
  211. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/concepts.py +0 -0
  212. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/config_watch.py +0 -0
  213. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/consolidate.py +0 -0
  214. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/core_memory.py +0 -0
  215. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/correlation.py +0 -0
  216. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/curator.py +0 -0
  217. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/dashboard.py +0 -0
  218. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/db_maintenance.py +0 -0
  219. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/dialectic.py +0 -0
  220. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/dialectic_feed.py +0 -0
  221. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/dialog.py +0 -0
  222. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/distill.py +0 -0
  223. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/evolve_applier.py +0 -0
  224. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/extract.py +0 -0
  225. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/forget.py +0 -0
  226. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/graph.py +0 -0
  227. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/invariants.py +0 -0
  228. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/lessons.py +0 -0
  229. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/memory_guard.py +0 -0
  230. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/missed_spawns.py +0 -0
  231. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/panel.py +0 -0
  232. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/peers.py +0 -0
  233. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/pickup.py +0 -0
  234. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/probes.py +0 -0
  235. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/process_health.py +0 -0
  236. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/prompts.py +0 -0
  237. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/resources.py +0 -0
  238. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/session.py +0 -0
  239. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/shadow_review.py +0 -0
  240. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/skills.py +0 -0
  241. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/spawn.py +0 -0
  242. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/style.py +0 -0
  243. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/sync.py +0 -0
  244. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/threads.py +0 -0
  245. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/tools/validate.py +0 -0
  246. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/trash.py +0 -0
  247. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/verify_ingest.py +0 -0
  248. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper/wikilinks.py +0 -0
  249. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/SOURCES.txt +0 -0
  250. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/dependency_links.txt +0 -0
  251. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/entry_points.txt +0 -0
  252. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/requires.txt +0 -0
  253. {threadkeeper-0.17.1 → threadkeeper-0.17.2}/threadkeeper.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadkeeper
3
- Version: 0.17.1
3
+ Version: 0.17.2
4
4
  Summary: Multi-agent shared brain across Claude Code/Desktop, Codex, Antigravity CLI, Copilot, and VS Code. Cross-session memory, self-improving skill loops, inter-agent signaling — one local MCP server.
5
5
  Author: thread-keeper contributors
6
6
  License: MIT
@@ -903,7 +903,12 @@ throttling the roadmap loop.
903
903
  Before any PR-producing reviewer/audit or applier child is spawned, the parent
904
904
  checks the target checkout with `git status --porcelain --untracked-files=no`.
905
905
  Tracked-file WIP records `skipped_dirty_worktree` and no child is dispatched;
906
- untracked scratch files do not block. Each managed-checkout child fetches the
906
+ the default managed checkout first preserves orphaned untracked files under
907
+ `~/.threadkeeper/evolve-recovery/untracked-*/` and removes them from the next
908
+ task’s tree. This prevents unrelated unfinished tests from blocking every PR
909
+ repair. Ignored files (including `.venv`) and explicit operator checkouts stay
910
+ in place; live writers prevent recovery, and backup failures block dispatch.
911
+ Each managed-checkout child fetches the
907
912
  configured branch only to retrieve the configured immutable commit, then
908
913
  prepares or resumes its deterministic local/remote feature branch from
909
914
  `THREADKEEPER_EVOLVE_REPO_COMMIT`, never from the branch's moving tip. Retries
@@ -859,7 +859,12 @@ throttling the roadmap loop.
859
859
  Before any PR-producing reviewer/audit or applier child is spawned, the parent
860
860
  checks the target checkout with `git status --porcelain --untracked-files=no`.
861
861
  Tracked-file WIP records `skipped_dirty_worktree` and no child is dispatched;
862
- untracked scratch files do not block. Each managed-checkout child fetches the
862
+ the default managed checkout first preserves orphaned untracked files under
863
+ `~/.threadkeeper/evolve-recovery/untracked-*/` and removes them from the next
864
+ task’s tree. This prevents unrelated unfinished tests from blocking every PR
865
+ repair. Ignored files (including `.venv`) and explicit operator checkouts stay
866
+ in place; live writers prevent recovery, and backup failures block dispatch.
867
+ Each managed-checkout child fetches the
863
868
  configured branch only to retrieve the configured immutable commit, then
864
869
  prepares or resumes its deterministic local/remote feature branch from
865
870
  `THREADKEEPER_EVOLVE_REPO_COMMIT`, never from the branch's moving tip. Retries
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "threadkeeper"
7
- version = "0.17.1"
7
+ version = "0.17.2"
8
8
  description = "Multi-agent shared brain across Claude Code/Desktop, Codex, Antigravity CLI, Copilot, and VS Code. Cross-session memory, self-improving skill loops, inter-agent signaling — one local MCP server."
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "thread-keeper contributors" }]
@@ -2540,6 +2540,9 @@ def test_ensure_repo_ready_recovers_dirty_managed_base_before_refresh(
2540
2540
  (repo / "shared.txt").write_text(
2541
2541
  "issue implementation left on main\n", encoding="utf-8"
2542
2542
  )
2543
+ (repo / "tests").mkdir()
2544
+ orphan = repo / "tests" / "test_other_issue.py"
2545
+ orphan.write_text("raise AssertionError('unrelated unfinished feature')\n")
2543
2546
  monkeypatch.setattr(
2544
2547
  pkg["ea"], "_prs_for_head_branch",
2545
2548
  lambda *args, **kwargs: (_ for _ in ()).throw(
@@ -2568,6 +2571,67 @@ def test_ensure_repo_ready_recovers_dirty_managed_base_before_refresh(
2568
2571
  ).fetchone()
2569
2572
  assert row["target"] == "managed_repo_refresh"
2570
2573
  assert "recovered_abandoned_wip branch=main" in row["summary"]
2574
+ assert not orphan.exists()
2575
+ saved = list((tmp_path / "evolve-recovery").glob("untracked-*/tests/*.py"))
2576
+ assert len(saved) == 1
2577
+ assert "unrelated unfinished feature" in saved[0].read_text()
2578
+
2579
+
2580
+ @pytest.mark.parametrize("mode", ["recover", "explicit", "live", "copy_error"])
2581
+ def test_untracked_recovery_preserves_work_and_isolates_next_validation(
2582
+ tmp_path, monkeypatch, mode,
2583
+ ):
2584
+ pkg = _bootstrap(tmp_path, monkeypatch, pin_repo=False)
2585
+ ea = pkg["ea"]
2586
+ repo = ea._managed_repo_dir()
2587
+ subprocess.run(["git", "init", str(repo)], check=True, capture_output=True)
2588
+ # Use Git's actual ignore rules, including filenames with spaces/newlines.
2589
+ (repo / ".git" / "info" / "exclude").write_text(".venv/\n")
2590
+ (repo / ".venv").mkdir()
2591
+ runtime = repo / ".venv" / "runtime"
2592
+ runtime.write_text("keep runtime")
2593
+ (repo / "tests").mkdir()
2594
+ source = repo / "tests" / "test_orphan with\nnewline.py"
2595
+ source.write_text("unfinished work\n")
2596
+ outside = tmp_path / "outside.txt"
2597
+ outside.write_text("external target")
2598
+ link = repo / "orphan-link"
2599
+ link.symlink_to(outside)
2600
+ if mode == "explicit":
2601
+ monkeypatch.setattr(ea, "EVOLVE_REPO_ROOT", str(repo))
2602
+ if mode == "live":
2603
+ monkeypatch.setattr(ea, "_running_git_writer_children", lambda conn: ["live"])
2604
+ if mode == "copy_error":
2605
+ def fail_copy(*args, **kwargs):
2606
+ raise OSError("backup unavailable")
2607
+ monkeypatch.setattr(ea.shutil, "copy2", fail_copy)
2608
+
2609
+ result = pkg["orig"]["_git_worktree_precondition"](
2610
+ pkg["db"].get_db(), repo, "conflict_repair"
2611
+ )
2612
+
2613
+ assert runtime.read_text() == "keep runtime"
2614
+ assert outside.read_text() == "external target"
2615
+ if mode == "recover":
2616
+ assert result == ""
2617
+ assert not source.exists() and not link.is_symlink()
2618
+ backups = list((tmp_path / "evolve-recovery").glob("untracked-*"))
2619
+ assert len(backups) == 1
2620
+ assert backups[0].stat().st_mode & 0o777 == 0o700
2621
+ assert (backups[0] / source.relative_to(repo)).read_text() == "unfinished work\n"
2622
+ assert (backups[0] / "orphan-link").is_symlink()
2623
+ assert pkg["orig"]["_git_worktree_precondition"](
2624
+ pkg["db"].get_db(), repo, "conflict_repair"
2625
+ ) == ""
2626
+ assert len(list((tmp_path / "evolve-recovery").glob("untracked-*"))) == 1
2627
+ else:
2628
+ assert source.read_text() == "unfinished work\n" and link.is_symlink()
2629
+ if mode == "live":
2630
+ assert result.startswith("evolve_git_writer_running")
2631
+ elif mode == "copy_error":
2632
+ assert "untracked_quarantine_failed" in result
2633
+ else:
2634
+ assert result == ""
2571
2635
 
2572
2636
 
2573
2637
  def test_managed_refresh_checks_live_writer_before_dirty_recovery(
@@ -56,6 +56,7 @@ import re
56
56
  import shutil
57
57
  import sqlite3
58
58
  import subprocess
59
+ import tempfile
59
60
  import threading
60
61
  import time
61
62
  from pathlib import Path
@@ -1001,6 +1002,49 @@ def _archive_tracked_diff(
1001
1002
  return path, ""
1002
1003
 
1003
1004
 
1005
+ def _quarantine_managed_untracked(repo_root: Path) -> tuple[str, str]:
1006
+ """Preserve a dead child's untracked files outside the next task's tree.
1007
+
1008
+ Call only after excluding live git writers. Ignored runtime files (including
1009
+ the virtualenv) stay in place; explicit operator checkouts are untouched.
1010
+ Copy the complete inventory before removing any source, so a backup failure
1011
+ cannot discard unfinished work or allow a contaminated validation run.
1012
+ """
1013
+ if not _managed_repo_auto_recovery_allowed(repo_root):
1014
+ return "", ""
1015
+ backup = None
1016
+ try:
1017
+ proc = subprocess.run(
1018
+ ["git", "-C", str(repo_root), "ls-files", "--others",
1019
+ "--exclude-standard", "-z"],
1020
+ capture_output=True, timeout=30, check=False,
1021
+ )
1022
+ if proc.returncode:
1023
+ return "", "untracked_inventory_failed"
1024
+ paths = [Path(os.fsdecode(p)) for p in proc.stdout.split(b"\0") if p]
1025
+ if not paths:
1026
+ return "", ""
1027
+ for relative in paths:
1028
+ source = repo_root / relative
1029
+ if (relative.is_absolute() or ".." in relative.parts
1030
+ or any((repo_root / p).is_symlink() for p in relative.parents)
1031
+ or not (source.is_file() or source.is_symlink())):
1032
+ return "", "untracked_inventory_unsafe_path"
1033
+ recovery_dir = DB_PATH.parent / "evolve-recovery"
1034
+ recovery_dir.mkdir(parents=True, exist_ok=True)
1035
+ recovery_dir.chmod(0o700)
1036
+ backup = Path(tempfile.mkdtemp(prefix="untracked-", dir=recovery_dir))
1037
+ for relative in paths:
1038
+ target = backup / relative
1039
+ target.parent.mkdir(parents=True, exist_ok=True)
1040
+ shutil.copy2(repo_root / relative, target, follow_symlinks=False)
1041
+ for relative in paths:
1042
+ (repo_root / relative).unlink()
1043
+ except (OSError, subprocess.TimeoutExpired) as exc:
1044
+ return "", f"untracked_quarantine_failed backup={backup} err={_short(str(exc))}"
1045
+ return f"quarantined_untracked n={len(paths)} backup={backup.name}", ""
1046
+
1047
+
1004
1048
  def _archive_stale_merge_diff(
1005
1049
  repo_root: Path,
1006
1050
  pr_number: int,
@@ -1284,8 +1328,8 @@ def _git_worktree_precondition(
1284
1328
  ) -> str:
1285
1329
  """Parent-side gate before spawning any child that may commit/push.
1286
1330
 
1287
- Untracked scratch files intentionally do not block, matching auto_update's
1288
- `git status --porcelain --untracked-files=no` safety contract.
1331
+ The managed checkout quarantines orphaned untracked files as well: pytest
1332
+ collects them even though the tracked-only Git safety check ignores them.
1289
1333
  """
1290
1334
  # Check durable/live writer state before inspecting dirty files: a current
1291
1335
  # child owns its WIP and must never be mistaken for an orphan eligible for
@@ -1295,6 +1339,13 @@ def _git_worktree_precondition(
1295
1339
  outcome = f"evolve_git_writer_running n={len(running)}"
1296
1340
  _record_git_safety_event(conn, actor, outcome)
1297
1341
  return outcome
1342
+ recovery, quarantine_err = _quarantine_managed_untracked(repo_root)
1343
+ if quarantine_err:
1344
+ outcome = f"ERR {quarantine_err}"
1345
+ _record_git_safety_event(conn, actor, outcome)
1346
+ return outcome
1347
+ if recovery:
1348
+ _record_git_safety_event(conn, actor, recovery)
1298
1349
  dirty, err = _tracked_worktree_status(repo_root)
1299
1350
  if err:
1300
1351
  outcome = f"ERR git_status_failed mode=git err={err}"
@@ -1424,6 +1475,11 @@ def _refresh_managed_repo(dest: Path) -> str:
1424
1475
  return f"ERR evolve_repo_refresh_running_check_failed={_short(str(e))}"
1425
1476
  if running:
1426
1477
  return f"ERR evolve_repo_refresh_in_use n={len(running)}"
1478
+ recovery, quarantine_err = _quarantine_managed_untracked(dest)
1479
+ if quarantine_err:
1480
+ return f"ERR evolve_repo_refresh_{quarantine_err}"
1481
+ if recovery:
1482
+ _record_git_safety_event(conn, "managed_repo_refresh", recovery)
1427
1483
  dirty, status_err = _tracked_worktree_status(dest)
1428
1484
  if status_err:
1429
1485
  return f"ERR evolve_repo_refresh_status_failed={_short(status_err)}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadkeeper
3
- Version: 0.17.1
3
+ Version: 0.17.2
4
4
  Summary: Multi-agent shared brain across Claude Code/Desktop, Codex, Antigravity CLI, Copilot, and VS Code. Cross-session memory, self-improving skill loops, inter-agent signaling — one local MCP server.
5
5
  Author: thread-keeper contributors
6
6
  License: MIT
@@ -903,7 +903,12 @@ throttling the roadmap loop.
903
903
  Before any PR-producing reviewer/audit or applier child is spawned, the parent
904
904
  checks the target checkout with `git status --porcelain --untracked-files=no`.
905
905
  Tracked-file WIP records `skipped_dirty_worktree` and no child is dispatched;
906
- untracked scratch files do not block. Each managed-checkout child fetches the
906
+ the default managed checkout first preserves orphaned untracked files under
907
+ `~/.threadkeeper/evolve-recovery/untracked-*/` and removes them from the next
908
+ task’s tree. This prevents unrelated unfinished tests from blocking every PR
909
+ repair. Ignored files (including `.venv`) and explicit operator checkouts stay
910
+ in place; live writers prevent recovery, and backup failures block dispatch.
911
+ Each managed-checkout child fetches the
907
912
  configured branch only to retrieve the configured immutable commit, then
908
913
  prepares or resumes its deterministic local/remote feature branch from
909
914
  `THREADKEEPER_EVOLVE_REPO_COMMIT`, never from the branch's moving tip. Retries
File without changes
File without changes