claude-code-conductor 2.43.0__tar.gz → 2.44.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.
Files changed (213) hide show
  1. claude_code_conductor-2.44.0/.claude/hooks/pre_compact.py +205 -0
  2. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/CHANGELOG.md +11 -0
  3. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/PKG-INFO +1 -1
  4. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/__init__.py +1 -1
  5. claude_code_conductor-2.44.0/tests/_pre_compact_helpers.py +88 -0
  6. claude_code_conductor-2.44.0/tests/test_pre_compact.py +1014 -0
  7. claude_code_conductor-2.44.0/tests/test_precompact_additional.py +149 -0
  8. claude_code_conductor-2.43.0/.claude/hooks/pre_compact.py +0 -61
  9. claude_code_conductor-2.43.0/tests/test_pre_compact.py +0 -265
  10. claude_code_conductor-2.43.0/tests/test_precompact_additional.py +0 -135
  11. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/CLAUDE.md +0 -0
  12. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/architect.md +0 -0
  13. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/code-reviewer.md +0 -0
  14. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/design-critic.md +0 -0
  15. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/developer.md +0 -0
  16. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/doc-writer.md +0 -0
  17. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/interviewer.md +0 -0
  18. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/planner.md +0 -0
  19. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/project-setup.md +0 -0
  20. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/security-reviewer.md +0 -0
  21. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/systematic-debugger.md +0 -0
  22. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/tester.md +0 -0
  23. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/wt_developer.md +0 -0
  24. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/wt_systematic-debugger.md +0 -0
  25. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/agents/wt_tester.md +0 -0
  26. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/breaking-changes.txt +0 -0
  27. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/deletions.txt +0 -0
  28. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/docs/config-policy.md +0 -0
  29. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/docs/parallel-agents-setup.md +0 -0
  30. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/docs/platform-adapters.md +0 -0
  31. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/docs/settings.json.md +0 -0
  32. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/_hook_utils.py +0 -0
  33. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/check_agent_invocation.py +0 -0
  34. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/consolidate_memory.py +0 -0
  35. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/permission_handler.py +0 -0
  36. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/permission_handler_toast.py +0 -0
  37. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/planner_check.py +0 -0
  38. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/post_tool.py +0 -0
  39. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/pre_tool.py +0 -0
  40. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/recall_autorebuild.py +0 -0
  41. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/recall_inject.py +0 -0
  42. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/restore_session.py +0 -0
  43. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/select_tier.py +0 -0
  44. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/session_start.py +0 -0
  45. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/session_stop.py +0 -0
  46. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/session_utils.py +0 -0
  47. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/statusline.py +0 -0
  48. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/stop.py +0 -0
  49. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/hooks/worktree_guard.py +0 -0
  50. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/memory/.gitkeep +0 -0
  51. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/permission_rules.json +0 -0
  52. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/rules/promoted/index.md +0 -0
  53. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/settings.json +0 -0
  54. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/brainstorm/SKILL.md +0 -0
  55. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/codex-review/SKILL.md +0 -0
  56. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
  57. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
  58. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
  59. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
  60. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
  61. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
  62. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
  63. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +0 -0
  64. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
  65. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
  66. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/develop/SKILL.md +0 -0
  67. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/doc/SKILL.md +0 -0
  68. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/extract-lib/SKILL.md +0 -0
  69. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/init-session/SKILL.md +0 -0
  70. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/init-session/scripts/session_guard.py +0 -0
  71. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/mcp-config/SKILL.md +0 -0
  72. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
  73. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/pattern-status/SKILL.md +0 -0
  74. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
  75. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/recall/SKILL.md +0 -0
  76. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
  77. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
  78. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/review-phase/SKILL.md +0 -0
  79. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/setup/SKILL.md +0 -0
  80. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/setup/reference.md +0 -0
  81. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
  82. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
  83. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/skills/start/SKILL.md +0 -0
  84. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.claude/state/.gitkeep +0 -0
  85. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/.gitignore +0 -0
  86. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/ARCHITECTURE.md +0 -0
  87. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSE +0 -0
  88. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSES/fastembed-LICENSE +0 -0
  89. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSES/fastembed-NOTICE +0 -0
  90. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSES/numpy-LICENSE +0 -0
  91. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSES/onnxruntime-LICENSE +0 -0
  92. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
  93. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/README.md +0 -0
  94. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/hatch_build.py +0 -0
  95. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/pyproject.toml +0 -0
  96. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/__main__.py +0 -0
  97. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/_db_params.py +0 -0
  98. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/_excludes.py +0 -0
  99. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/_terminal.py +0 -0
  100. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/adapters.py +0 -0
  101. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli.py +0 -0
  102. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_ask.py +0 -0
  103. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_doctor.py +0 -0
  104. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_init.py +0 -0
  105. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_list.py +0 -0
  106. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_plan.py +0 -0
  107. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_recall.py +0 -0
  108. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_tier.py +0 -0
  109. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/cli_update.py +0 -0
  110. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/db.py +0 -0
  111. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/embedding.py +0 -0
  112. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/gitutil.py +0 -0
  113. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/mcp_server.py +0 -0
  114. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrate.py +0 -0
  115. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/001_initial.sql +0 -0
  116. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
  117. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/003_tier_cost.sql +0 -0
  118. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/004_agent_outcomes.sql +0 -0
  119. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
  120. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/README.md +0 -0
  121. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/migrations/__init__.py +0 -0
  122. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/paths.py +0 -0
  123. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/plan_validator.py +0 -0
  124. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/platforms.py +0 -0
  125. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/pricing.py +0 -0
  126. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/question.py +0 -0
  127. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/recall_chunker.py +0 -0
  128. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/recall_index.py +0 -0
  129. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/src/c3/usage_ingester.py +0 -0
  130. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/__init__.py +0 -0
  131. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/conftest.py +0 -0
  132. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/fixtures/usage/README.md +0 -0
  133. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/fixtures/usage/mainline.jsonl +0 -0
  134. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
  135. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
  136. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/__init__.py +0 -0
  137. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_check_agent_invocation.py +0 -0
  138. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_consolidate_memory.py +0 -0
  139. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_hook_utils.py +0 -0
  140. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_permission_handler.py +0 -0
  141. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_permission_handler_toast.py +0 -0
  142. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
  143. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_planner_check.py +0 -0
  144. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_planner_check_dev.py +0 -0
  145. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_post_tool.py +0 -0
  146. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_pre_tool.py +0 -0
  147. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_recall_autorebuild.py +0 -0
  148. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_recall_inject.py +0 -0
  149. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_record_agent_outcome.py +0 -0
  150. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_record_review_decision.py +0 -0
  151. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_restore_session.py +0 -0
  152. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_review_hint_inject.py +0 -0
  153. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_select_tier.py +0 -0
  154. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_select_tier_escalation.py +0 -0
  155. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_session_start.py +0 -0
  156. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_session_stop.py +0 -0
  157. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_session_utils.py +0 -0
  158. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
  159. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_similarity_boost.py +0 -0
  160. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_statusline.py +0 -0
  161. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_statusline_template_sync.py +0 -0
  162. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_sync_check.py +0 -0
  163. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/hooks/test_template_guard.py +0 -0
  164. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/__init__.py +0 -0
  165. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/_skill_helpers.py +0 -0
  166. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
  167. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_init_session_no_task_type.py +0 -0
  168. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_planner_lightweight.py +0 -0
  169. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_recall_skill.py +0 -0
  170. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
  171. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_session_guard.py +0 -0
  172. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_setup_templates.py +0 -0
  173. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
  174. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_start_skill_new_flow.py +0 -0
  175. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
  176. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_adapters.py +0 -0
  177. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_check_deletions.py +0 -0
  178. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_ask.py +0 -0
  179. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_doctor.py +0 -0
  180. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_entry.py +0 -0
  181. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_init.py +0 -0
  182. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_list.py +0 -0
  183. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_plan.py +0 -0
  184. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_recall.py +0 -0
  185. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_tier.py +0 -0
  186. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_update_breaking_changes.py +0 -0
  187. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_cli_update_deletions.py +0 -0
  188. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_db.py +0 -0
  189. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_docstring_consistency.py +0 -0
  190. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_embedding.py +0 -0
  191. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_excludes.py +0 -0
  192. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_extract_breaking_changes.py +0 -0
  193. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_gitutil.py +0 -0
  194. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_mcp_server_elicit.py +0 -0
  195. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_migrate.py +0 -0
  196. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_paths.py +0 -0
  197. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_plan_validator.py +0 -0
  198. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_pre_tool_hook.py +0 -0
  199. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_precompact_toctou_fixes.py +0 -0
  200. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_pricing.py +0 -0
  201. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_recall_chunker.py +0 -0
  202. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_recall_index.py +0 -0
  203. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_references_migration.py +0 -0
  204. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_session_utils_additional.py +0 -0
  205. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_skill_no_builtin_conflict.py +0 -0
  206. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_statusline.py +0 -0
  207. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_stop_additional.py +0 -0
  208. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_stop_hook.py +0 -0
  209. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_stop_precompact_fixes.py +0 -0
  210. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_sync_template_stop.py +0 -0
  211. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_template_pre_tool_hook.py +0 -0
  212. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_usage_ingester.py +0 -0
  213. {claude_code_conductor-2.43.0 → claude_code_conductor-2.44.0}/tests/test_worktree_guard.py +0 -0
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ """PreCompact hook: append checkpoint marker (デバウンス付き)。
3
+
4
+ 直近 DEBOUNCE_WINDOW_SECONDS 秒以内に PreCompact checkpoint が既に存在する場合は、
5
+ checkpoint の追記をスキップする(PreCompact の連続起動による重複追記を防ぐ
6
+ デバウンス機構)。
7
+ """
8
+
9
+ import json
10
+ import os
11
+ import re
12
+ import sys
13
+ from datetime import datetime, timedelta, timezone
14
+
15
+ sys.stdout.reconfigure(encoding='utf-8')
16
+ sys.stderr.reconfigure(encoding='utf-8')
17
+
18
+ from session_utils import SESSION_JSON_MARKER, append_checkpoint, is_worktree, SESSIONS_DIR
19
+
20
+
21
+ # デバウンス窓幅(秒)。直近の PreCompact checkpoint からこの秒数以内の再実行は
22
+ # 追記をスキップする(4連続起動の重複防止)。
23
+ DEBOUNCE_WINDOW_SECONDS = 10
24
+
25
+ # checkpoint 行抽出のため splitlines() に渡す前に除去する行区切り文字パターン。
26
+ # stop.py::_INHERIT_SANITIZE_RE / session_utils._VALUE_SANITIZE_RE と同一範囲(対称)。
27
+ # str.splitlines() は \n 以外に \v / \f / \x1c-\x1e / \x85 / U+2028 / U+2029 でも
28
+ # 行分割する。append_checkpoint が書き込む summary body(未サニタイズの trigger 等)に
29
+ # これらの文字+checkpoint 行に酷似する文字列が混入すると、splitlines() が偽の行を
30
+ # 生成し _PRECOMPACT_CHECKPOINT_RE が誤マッチしてデバウンスの偽陽性を起こし得る。
31
+ # stop.py の _inherit_pending_tasks と同趣旨で、分割前に事前除去する。
32
+ # raw string は \uXXXX を解釈しないため U+2028 / U+2029 は chr() で連結する。
33
+ _LINE_SEPARATOR_SANITIZE_RE = re.compile(
34
+ r'[\x00-\x08\x0b-\x1f\x7f-\x9f' + chr(0x2028) + chr(0x2029) + r']'
35
+ )
36
+
37
+ # checkpoint 行の固定プレフィックス。PreCompact ラベルへのアンカーとして使う
38
+ # (他ラベル、例えば Wave checkpoint を除外する)。
39
+ _PRECOMPACT_CHECKPOINT_PREFIX = '## [Checkpoint: PreCompact:'
40
+
41
+ # checkpoint 行として許容する最大長(fix-cycle-2, security-review-report-20260704-075817.md
42
+ # [SR-NEW])。正規の checkpoint ヘッダ行は数十〜数百文字で十分なため、これを超える行は
43
+ # パース対象から除外する(regex 撤去後の belt-and-suspenders ガード)。
44
+ MAX_CHECKPOINT_LINE_LEN = 512
45
+
46
+ # parse 成功した timestamp が `now` をこの秒数を超えて上回る場合、構造的異常値として
47
+ # 棄却する(fail-open)。checkpoint の timestamp は append_checkpoint が同一ホストの
48
+ # UTC 実時刻で書くため、書き込み時刻は必ず読み取り時刻以前になるはず。
49
+ #
50
+ # 60 秒は独立したセキュリティ判断としての保守値である。正当な checkpoint 行の
51
+ # timestamp が読み取り時刻をわずかに上回り得る唯一の現実的経路は、NTP による
52
+ # クライアント時計の後方ステップ補正(書き込み時点で実時刻より進んでいた時計が、
53
+ # 読み取り時点までに巻き戻される)であり、この巻き戻し幅を吸収するために許容する。
54
+ # 通常の NTP ステップ補正は秒〜十数秒規模のため 60 秒あれば十分に吸収できる。
55
+ #
56
+ # この値を大きく取り過ぎると、許容スキュー以内の未来日時 checkpoint を注入された
57
+ # 場合に、実時刻がその timestamp に追いつくまでデバウンスが効き続け、checkpoint 追記
58
+ # が最大で許容秒数ぶん停止する([SR-V-001])。60 秒に
59
+ # 抑えることで、悪意ある注入・データ破損いずれの場合も最大デバウンス停止時間を
60
+ # 60 秒以内に限定する。
61
+ #
62
+ # 未来スキューを跨いだ許容/棄却境界はテスト側で module.FUTURE_SKEW_TOLERANCE_SECONDS
63
+ # を参照した相対時刻テストとして固定しており、テストは now= を明示指定して壁時計に
64
+ # 依存しない(値をテストフィクスチャ都合で膨らませる必要はない)。
65
+ FUTURE_SKEW_TOLERANCE_SECONDS = 60
66
+
67
+ # parse 失敗時の stderr 診断ログに出す捕捉テキストの最大長
68
+ # (fix-cycle-2, security-review-report-20260704-075817.md [SR-R-001])。
69
+ DIAGNOSTIC_MAX_LEN = 64
70
+
71
+
72
+ def _last_precompact_checkpoint_dt(session_file, now=None):
73
+ """session_file 内の最後の PreCompact checkpoint 行から aware datetime を返す。
74
+
75
+ ファイル無し・PreCompact 行無し・parse 不能・naive datetime・未来日時(許容
76
+ スキュー超)など、あらゆる異常系で None を返す(fail-open の中核)。
77
+
78
+ `now` は未来日時ガードの基準時刻(省略時は呼び出し時点の UTC 実時刻)。
79
+ 呼び出し元(main)と判定基準を一致させたい場合は明示的に渡すこと。
80
+ """
81
+ if now is None:
82
+ now = datetime.now(timezone.utc)
83
+
84
+ try:
85
+ with open(session_file, encoding='utf-8') as f:
86
+ content = f.read()
87
+ except (OSError, ValueError, TypeError):
88
+ # 「ファイル無し」は初回起動時の通常ケース。ほぼ毎日 1 回 stderr へ
89
+ # 出すとスパムになるため、ここでは無音のまま fail-open する(CR-L-003)。
90
+ return None
91
+
92
+ # splitlines() が特殊行区切り文字(\x85 / U+2028 / U+2029 等)で偽の checkpoint
93
+ # 行を生成しないよう、分割前に除去する(stop.py と対称なガード / CR-NEW Medium)。
94
+ lines = _LINE_SEPARATOR_SANITIZE_RE.sub('', content).splitlines()
95
+
96
+ for line in reversed(lines):
97
+ # regex(`.* - (.+)`)の二重ワイルドカードによる多項式時間バックトラッキング
98
+ # (ReDoS)を根絶するため、手続き的パースに置き換える
99
+ # (fix-cycle-2, security-review-report-20260704-075817.md [SR-NEW])。
100
+ stripped = line.rstrip()
101
+ if len(stripped) > MAX_CHECKPOINT_LINE_LEN:
102
+ # 行長ガード。異常に長い行は正規の checkpoint ではあり得ないため
103
+ # 以降のパース処理(rfind 等)に進む前にスキップする。
104
+ continue
105
+ if not stripped.startswith(_PRECOMPACT_CHECKPOINT_PREFIX):
106
+ continue
107
+ if not stripped.endswith(']'):
108
+ continue
109
+ # プレフィックスと末尾 `]` を除いた内側の文字列から、最後の ` - ` を
110
+ # timestamp との区切りとみなす(旧 greedy regex `.* - (.+)]` の「最後の
111
+ # ` - ` フィールドを timestamp とする」挙動と等価。label 内の偶発的な
112
+ # ` - ` があっても安全側に倒れる)。
113
+ # 旧 regex は `(.+)` が 1 文字以上を要求するため、timestamp 欄が完全空文字の
114
+ # 行(例: `## [Checkpoint: PreCompact: manual - ]`)を非マッチとして扱い、
115
+ # より古い有効な checkpoint 行を探し続けていた。空 ts_text を continue で
116
+ # スキップすることで、この空文字境界でも旧 regex と等価に振る舞う。
117
+ inner = stripped[len(_PRECOMPACT_CHECKPOINT_PREFIX):-1]
118
+ sep_idx = inner.rfind(' - ')
119
+ if sep_idx == -1:
120
+ continue
121
+ ts_text = inner[sep_idx + len(' - '):].strip()
122
+ if not ts_text:
123
+ # 空文字 timestamp は旧 greedy regex `(.+)` の非マッチに相当する。
124
+ # 診断ログは出さず(破損ではなく単なる欠落のため)、より古い有効行の
125
+ # 探索を継続する。
126
+ continue
127
+ try:
128
+ dt = datetime.fromisoformat(ts_text)
129
+ except (ValueError, TypeError):
130
+ # 「timestamp が壊れている」のは本来発生しない想定外の破損ケース。
131
+ # ファイル無しの通常ケースと異なり、将来のトラブルシュートのため
132
+ # このケースに限り stderr へ診断ログを 1 行出す(CR-L-003・非対称仕様)。
133
+ # 捕捉テキストは固定長に切り詰めて出力する(SR-R-001)。
134
+ # 戻り値は引き続き None(fail-open で追記継続)。
135
+ print(
136
+ '[PreCompact] 診断: checkpoint 行の timestamp を parse できませんでした'
137
+ f'(fail-open で追記を継続します): {ts_text[:DIAGNOSTIC_MAX_LEN]!r}',
138
+ file=sys.stderr,
139
+ )
140
+ return None
141
+ if dt.tzinfo is None:
142
+ return None
143
+ if dt > now + timedelta(seconds=FUTURE_SKEW_TOLERANCE_SECONDS):
144
+ # 未来日時(許容スキュー超)は構造的異常値として棄却する(fail-open)。
145
+ # 悪意ある注入・データ破損いずれの場合も、デバウンスの恒久停止を
146
+ # 招かないよう None を返して追記を継続する
147
+ # (fix-cycle-2, security-review-report-20260704-075817.md [SR-V-001])。
148
+ return None
149
+ return dt
150
+
151
+ return None
152
+
153
+
154
+ def main():
155
+ try:
156
+ payload = json.loads(sys.stdin.read())
157
+ except (json.JSONDecodeError, ValueError):
158
+ payload = {}
159
+
160
+ cwd = os.getcwd()
161
+ if is_worktree(cwd):
162
+ sys.exit(0)
163
+
164
+ trigger = payload.get('trigger', 'unknown')
165
+ context_items_before = payload.get('context_items_before')
166
+ context_items_before_str = 'N/A' if context_items_before is None else str(context_items_before)
167
+
168
+ now = datetime.now(timezone.utc)
169
+ # 既知の構造的限界(CR-NEW Low・修正しない): session_file は now の UTC 日付から
170
+ # 算出する。PreCompact の連続起動(実測 約1.2 秒スパン)が UTC 00:00:00 ちょうどを
171
+ # またぐ極稀ケースでは、前後の呼び出しが別日の session_file を参照するため
172
+ # デバウンス判定が効かず checkpoint が二重追記され得る。発生確率は極小のため
173
+ # コードでは対処せず既知の限界として許容する。
174
+ date_str = now.strftime('%Y%m%d')
175
+ session_file = os.path.join(SESSIONS_DIR, f'{date_str}.tmp')
176
+
177
+ last = _last_precompact_checkpoint_dt(session_file, now=now)
178
+ if last is not None and (now - last) < timedelta(seconds=DEBOUNCE_WINDOW_SECONDS):
179
+ print('[PreCompact] debounce: 直近の checkpoint を検出したため追記をスキップしました', file=sys.stderr)
180
+ return
181
+
182
+ # セキュリティ非対称性の記録(fix-cycle-2, security-review-report-20260704-121824.md
183
+ # [SR-V-001]・情報提供・現状は対応不要): 以下の summary(body)は
184
+ # session_utils.append_checkpoint の設計上 sanitize_value() 非適用で書き込まれる
185
+ # (複数行 Markdown を保持するための承認済み設計判断・session_utils.py L147 参照)。
186
+ # そのため body に埋め込む trigger(L164)は未サニタイズのまま checkpoint に書かれる。
187
+ # 一方 label(下の f'PreCompact: {trigger}')は append_checkpoint 内で
188
+ # sanitize_value() を通るため、body と label で sanitize 適用範囲に非対称性がある。
189
+ # 現状 trigger は Claude Code ハーネスが設定する列挙的な値(manual/auto 等)で、
190
+ # 外部入力・LLM 自由記述からの直接汚染経路が無いため実害の確信度は低い。
191
+ # 【将来の拡張時の注意】trigger の由来をハーネス以外(プラグイン・カスタムフック
192
+ # 連携等)に拡張する場合は、偽 checkpoint 注入経路化を防ぐため body 側にも
193
+ # sanitize_value() 適用を検討すること。
194
+ summary = (
195
+ f"- trigger: {trigger}\n"
196
+ f"- context_items_before: {context_items_before_str}\n"
197
+ f"- このポイント以前の詳細な文脈は圧縮により失われます。"
198
+ )
199
+ append_checkpoint(session_file, f'PreCompact: {trigger}', summary)
200
+
201
+ print(f'[PreCompact] セッション状態を {session_file} に保存しました', file=sys.stderr)
202
+
203
+
204
+ if __name__ == '__main__':
205
+ main()
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.44.0] - 2026-07-04
4
+
5
+ ### 修正
6
+
7
+ - **PreCompact checkpoint の多重発火をデバウンスで冪等化**: Claude Code ハーネスは 1 回の `/compact` で PreCompact hook を複数回起動することがあり(実測 2〜4 回・payload 違い・公式 docs 非記載の undocumented 挙動)、セッションファイルに同一 checkpoint ブロックが堆積していた(実測で 1 日分ファイルの約 8 割がノイズ化し、翌セッション復元時の読み込みコンテキストを浪費)。`pre_compact.py` が追記前に当日セッションファイル末尾の PreCompact checkpoint timestamp を読み、10 秒以内の再起動なら追記をスキップする。timestamp 不在・parse 不能時は fail-open(従来どおり追記)。実装には ReDoS 対策(行長 512 上限・正規表現を使わない手続きパース)・未来日時 checkpoint の棄却(スキュー許容 60 秒・デバウンス恒久停止の防止)・行区切り文字サニタイズ・stderr 診断ログの切り詰め(64 字)を含む。実機 E2E で 1 compact = 1 ブロックを確認済み。
8
+ - **PreCompact hook の仕様外 additionalContext stdout 出力を撤去**: PreCompact は公式仕様上 `hookSpecificOutput.additionalContext` をサポートしない(サポートされるのは top-level `decision: "block"` + `reason` のみ)。C3 は従来この仕様外 JSON を stdout に出力しており、現行ハーネスの `/compact` で「PreCompact hook JSON output validation failed」警告を誘発していた(additionalContext の注入自体もモデルに届いていた保証がない)。`pre_compact.py` を checkpoint 追記専念に変更し、JSON stdout 出力と `SAVE_INSTRUCTION` 定数を削除。セッションファイルの更新は運用ルール(現在地の常時更新・タスク完了ごとの更新)で担保されているため機能上の後退はない。実機で警告の消滅を確認済み。
9
+
10
+ ### 後方互換
11
+
12
+ - `.claude/hooks/pre_compact.py` とそのテストのみの変更で `src/c3/` に変更なし。**破壊的変更なし**。`session_utils.append_checkpoint()` の契約(parallel-agents の wave checkpoint と共用)・`settings.json` の hook 登録は不変。
13
+
3
14
  ## [2.43.0] - 2026-07-03
4
15
 
5
16
  ### 変更
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-conductor
3
- Version: 2.43.0
3
+ Version: 2.44.0
4
4
  Summary: Multi-agent orchestration framework for Claude Code with Codex/Cursor adapters (C3)
5
5
  Project-URL: Homepage, https://github.com/satoh-y-0323/claude-code-conductor
6
6
  Project-URL: Repository, https://github.com/satoh-y-0323/claude-code-conductor
@@ -1,3 +1,3 @@
1
1
  """Claude Code Conductor (C3) - multi-agent orchestration framework for Claude Code."""
2
2
 
3
- __version__ = "2.43.0"
3
+ __version__ = "2.44.0"
@@ -0,0 +1,88 @@
1
+ """
2
+ tests/_pre_compact_helpers.py
3
+
4
+ .claude/hooks/pre_compact.py 系テスト(tests/test_pre_compact.py /
5
+ tests/test_precompact_additional.py)で共通利用するヘルパー。
6
+
7
+ - WORKTREE_ROOT / PRE_COMPACT_PY: pre_compact.py の絶対パス
8
+ - _load_pre_compact_module(): pre_compact.py をモジュールとしてロードする(__main__ 実行なし)
9
+ - _run_main_in_process(): pre_compact.py の main() を in-process 実行し、実 sessions dir に
10
+ 一切触れない(architecture-report-20260704-065052.md §4.2 / §8-1 案 A の in-process 方式)
11
+
12
+ 意図: 旧来は tests/test_pre_compact.py と tests/test_precompact_additional.py の両方で
13
+ `_load_pre_compact_module()` / `_run_main_in_process()` をほぼ同一実装のまま重複定義していた
14
+ (CR-M-001)。前例 `tests/skills/_skill_helpers.py` に倣い、本モジュールへ一本化する。
15
+
16
+ `_run_main_in_process()` の戻り値は `(module, sessions_dir, fake_stdout)` の 3-tuple。
17
+ `test_pre_compact.py` は 3 値すべてを使用する。`test_precompact_additional.py` は
18
+ `fake_stdout` のみを使うため、呼び出し側で `_, _, fake_stdout = _run_main_in_process(...)`
19
+ のように必要な要素だけ取り出す(stdout の値・main() の実行内容は従来と不変更)。
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import importlib.util
25
+ import io
26
+ import json
27
+ import os
28
+ import sys
29
+ import types
30
+ from pathlib import Path
31
+
32
+ import pytest
33
+
34
+ # ---------------------------------------------------------------------------
35
+ # Paths
36
+ # ---------------------------------------------------------------------------
37
+
38
+ WORKTREE_ROOT = Path(__file__).resolve().parent.parent
39
+ PRE_COMPACT_PY = WORKTREE_ROOT / ".claude" / "hooks" / "pre_compact.py"
40
+
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # Helpers
44
+ # ---------------------------------------------------------------------------
45
+
46
+
47
+ def _load_pre_compact_module() -> types.ModuleType:
48
+ """pre_compact.py をモジュールとしてロードする(__main__ 実行なし)。
49
+
50
+ pre_compact.py はモジュールレベルで session_utils を import するため、
51
+ sys.path に hooks ディレクトリを追加してからロードする。
52
+ """
53
+ hooks_dir = str(PRE_COMPACT_PY.parent)
54
+ if hooks_dir not in sys.path:
55
+ sys.path.insert(0, hooks_dir)
56
+ spec = importlib.util.spec_from_file_location("pre_compact", PRE_COMPACT_PY)
57
+ assert spec is not None and spec.loader is not None
58
+ module = importlib.util.module_from_spec(spec)
59
+ spec.loader.exec_module(module) # type: ignore[attr-defined]
60
+ return module
61
+
62
+
63
+ def _run_main_in_process(
64
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path, payload: dict
65
+ ) -> tuple[types.ModuleType, Path, io.StringIO]:
66
+ """pre_compact.py の main() を in-process 実行し、実 sessions dir に一切触れない。
67
+
68
+ architecture-report-20260704-065052.md §4.2 の in-process 方式(T1 の
69
+ TestMainDebounce と同一パターン):
70
+ - `mod.SESSIONS_DIR` を tmp_path 配下に override
71
+ - `sys.stdin` を JSON payload の StringIO に差し替え
72
+ - `os.getcwd` を tmp_path に固定して非 worktree 経路を保証
73
+ - `sys.stdout` を明示的に StringIO に差し替えて捕捉する
74
+ (capsys は使わない。reconfigure 済み hook では capsys が効かない
75
+ 場合があるため。tests/agent-memory の I-01 パターンに準拠)
76
+ """
77
+ module = _load_pre_compact_module()
78
+ sessions_dir = tmp_path / "sessions"
79
+ sessions_dir.mkdir(parents=True, exist_ok=True)
80
+ monkeypatch.setattr(module, "SESSIONS_DIR", str(sessions_dir))
81
+ monkeypatch.setattr(os, "getcwd", lambda: str(tmp_path))
82
+ monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(payload)))
83
+ fake_stdout = io.StringIO()
84
+ monkeypatch.setattr(sys, "stdout", fake_stdout)
85
+
86
+ module.main()
87
+
88
+ return module, sessions_dir, fake_stdout