claude-code-conductor 2.15.2__tar.gz → 2.16.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.
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/stop.py +130 -8
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/CHANGELOG.md +67 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/PKG-INFO +1 -1
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/__init__.py +1 -1
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_stop_additional.py +504 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/agents/wt_tester.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/docs/platform-adapters.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/_hook_utils.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/permission_handler.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/permission_handler_toast.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/schema.sql +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/permission_rules.json +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/settings.json +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/codex-review/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/scripts/record_tier_outcome.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/init-session/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/skills/start/SKILL.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/.gitignore +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/chroma-hnswlib-LICENSE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/chroma-hnswlib-NOTICE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/README.md +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/hatch_build.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/pyproject.toml +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/adapters.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_ask.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/db.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/question.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/__init__.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/conftest.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_hook_utils.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_permission_handler.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_permission_handler_toast.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_record_tier_outcome.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/_skill_helpers.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_init_session_no_task_type.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_start_skill_new_flow.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_adapters.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_ask.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_cli_update.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_db.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.15.2 → claude_code_conductor-2.16.0}/tests/test_worktree_guard.py +0 -0
|
@@ -11,7 +11,7 @@ import re
|
|
|
11
11
|
import tempfile
|
|
12
12
|
from datetime import date, datetime, timezone
|
|
13
13
|
|
|
14
|
-
from session_utils import SESSION_JSON_MARKER, is_worktree, create_session_template, SESSIONS_DIR, ensure_session_initialized
|
|
14
|
+
from session_utils import SESSION_JSON_MARKER, is_worktree, create_session_template, SESSIONS_DIR, ensure_session_initialized, extract_section
|
|
15
15
|
|
|
16
16
|
try:
|
|
17
17
|
sys.stdin.reconfigure(encoding='utf-8')
|
|
@@ -31,6 +31,14 @@ MAX_ID_LENGTH = 64
|
|
|
31
31
|
MAX_DESCRIPTION_LENGTH = 500
|
|
32
32
|
MAX_LAST_MSG = 500
|
|
33
33
|
|
|
34
|
+
# 過去セッションファイルから引き継ぐ - [ ] 行のサニタイズ用パターン。
|
|
35
|
+
# C0/C1 制御文字 (タブ と通常スペース は保持) と U+2028 / U+2029 を除去する。
|
|
36
|
+
# 過去ファイルの ## 残タスク はユーザー編集領域のため信頼境界として扱う [SR-V-001]。
|
|
37
|
+
# raw string は \uXXXX を解釈しないため、U+2028 / U+2029 は chr() で生成して連結する。
|
|
38
|
+
_INHERIT_SANITIZE_RE = re.compile(
|
|
39
|
+
r'[\x00-\x08\x0b-\x1f\x7f-\x9f' + chr(0x2028) + chr(0x2029) + r']'
|
|
40
|
+
)
|
|
41
|
+
|
|
34
42
|
# _append_last_message が処理済みのパスを記録するキャッシュ(重複 read/write 防止)。
|
|
35
43
|
_last_message_applied_paths: set = set()
|
|
36
44
|
|
|
@@ -39,6 +47,99 @@ def get_session_path(date_str: str) -> str:
|
|
|
39
47
|
return os.path.join(SESSIONS_DIR, f'{date_str}.tmp')
|
|
40
48
|
|
|
41
49
|
|
|
50
|
+
def _inherit_backlog_from_latest_session(
|
|
51
|
+
new_path: str, today_str: str, sessions_dir: str | None = None
|
|
52
|
+
) -> None:
|
|
53
|
+
"""新規セッションファイルに、直近過去セッションの未完了バックログを引き継ぐ。
|
|
54
|
+
|
|
55
|
+
過去ファイルの ``## 残タスク`` セクションから ``- [ ]`` 行のみ抽出し、
|
|
56
|
+
新規ファイルの ``## 残タスク`` セクションに追記する。``- [x]`` 行は対象外。
|
|
57
|
+
マルチライン継続行(インデントされた `- [ ]` 以外の継続行)は引き継がない。
|
|
58
|
+
|
|
59
|
+
本ヘルパーは `ensure_session_file` の新規作成パスからのみ呼ばれる。既存当日
|
|
60
|
+
ファイルが存在する場合は呼ばれないため、ユーザー編集を上書きする危険はない。
|
|
61
|
+
|
|
62
|
+
過去ファイルから引き継ぐ行は `_INHERIT_SANITIZE_RE` で制御文字・ANSI エスケープ・
|
|
63
|
+
U+2028/U+2029 を除去してから書き込むため、過去ファイルの改ざんによる端末
|
|
64
|
+
インジェクションは構造的に防御される [SR-V-001]。
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
new_path: 新規作成された当日セッションファイルのパス。
|
|
68
|
+
today_str: 今日の日付(YYYYMMDD)。これ未満の日付の .tmp が対象。
|
|
69
|
+
sessions_dir: SESSIONS_DIR を上書きしたい場合のテスト用引数。
|
|
70
|
+
None の場合はモジュールグローバル SESSIONS_DIR を使う。
|
|
71
|
+
"""
|
|
72
|
+
_sessions_dir = sessions_dir if sessions_dir is not None else SESSIONS_DIR
|
|
73
|
+
if not os.path.isdir(_sessions_dir):
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
# 今日より前で最大の日付(= 直近過去セッション)を選ぶ
|
|
77
|
+
past_dates = [
|
|
78
|
+
fname[:-4] for fname in os.listdir(_sessions_dir)
|
|
79
|
+
if fname.endswith('.tmp') and fname[:-4] < today_str
|
|
80
|
+
]
|
|
81
|
+
if not past_dates:
|
|
82
|
+
return
|
|
83
|
+
latest_past_path = os.path.join(_sessions_dir, f'{max(past_dates)}.tmp')
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
# universal newlines(デフォルト)で読み込む。攻撃により \r 単体が混入しても
|
|
87
|
+
# この時点で \n に変換されるため、\r 単体は構造的に防御される。
|
|
88
|
+
# ただし Python の str.splitlines() は \n に加え \v / \f / \x1c / \x1d / \x1e /
|
|
89
|
+
# \x85 / U+2028 / U+2029 でも分割する。これらは _INHERIT_SANITIZE_RE で
|
|
90
|
+
# 事前に除去してから splitlines に渡す必要がある。
|
|
91
|
+
with open(latest_past_path, 'r', encoding='utf-8') as f:
|
|
92
|
+
past_content = f.read()
|
|
93
|
+
except OSError:
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
# U+2028/U+2029 等の行区切り文字を事前にサニタイズしてから splitlines するため、
|
|
97
|
+
# 過去ファイルに混入した行区切り文字によって意図しない行分割が発生しない。
|
|
98
|
+
backlog_section = extract_section(past_content, '残タスク')
|
|
99
|
+
sanitized_section = _INHERIT_SANITIZE_RE.sub('', backlog_section)
|
|
100
|
+
pending_tasks = [
|
|
101
|
+
line for line in sanitized_section.splitlines()
|
|
102
|
+
if line.lstrip().startswith('- [ ]')
|
|
103
|
+
]
|
|
104
|
+
if not pending_tasks:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
with open(new_path, 'r', encoding='utf-8') as f:
|
|
109
|
+
new_content = f.read()
|
|
110
|
+
except OSError:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
inheritance_block = '\n'.join(pending_tasks) + '\n'
|
|
114
|
+
updated = new_content.replace(
|
|
115
|
+
'## 残タスク\n',
|
|
116
|
+
f'## 残タスク\n{inheritance_block}',
|
|
117
|
+
1,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if updated == new_content:
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
# アトミック書き込み: _apply_session_updates と同じ tempfile + os.replace パターン。
|
|
124
|
+
# suffix='.writing' は SESSIONS_DIR 内の `.tmp` 一覧フィルタに引っかからないよう
|
|
125
|
+
# 構造的に隔離する [SR-NEW L-1]。
|
|
126
|
+
dir_ = os.path.dirname(new_path)
|
|
127
|
+
tmp_path = None
|
|
128
|
+
try:
|
|
129
|
+
tmp_fd, tmp_path = tempfile.mkstemp(dir=dir_, suffix='.writing')
|
|
130
|
+
try:
|
|
131
|
+
with os.fdopen(tmp_fd, 'w', encoding='utf-8') as tmp_f:
|
|
132
|
+
tmp_f.write(updated)
|
|
133
|
+
except Exception:
|
|
134
|
+
os.close(tmp_fd)
|
|
135
|
+
raise
|
|
136
|
+
os.replace(tmp_path, new_path)
|
|
137
|
+
tmp_path = None
|
|
138
|
+
finally:
|
|
139
|
+
if tmp_path is not None and os.path.exists(tmp_path):
|
|
140
|
+
os.unlink(tmp_path)
|
|
141
|
+
|
|
142
|
+
|
|
42
143
|
def ensure_session_file(date_str: str) -> None:
|
|
43
144
|
os.makedirs(SESSIONS_DIR, exist_ok=True)
|
|
44
145
|
path = get_session_path(date_str)
|
|
@@ -46,6 +147,11 @@ def ensure_session_file(date_str: str) -> None:
|
|
|
46
147
|
try:
|
|
47
148
|
with open(path, 'x', encoding='utf-8') as f:
|
|
48
149
|
f.write(create_session_template(date_str))
|
|
150
|
+
# 新規作成時のみ、直近過去セッションから未完了タスクを引き継ぐ。
|
|
151
|
+
# 既存ファイルがある場合 (FileExistsError ブランチ) はユーザー編集を尊重し
|
|
152
|
+
# 引き継ぎを発動しない。sessions_dir を明示渡しにすることで、引き継ぎ関数内
|
|
153
|
+
# の SESSIONS_DIR 直参照を排除し、テスト時のグローバル差し替え依存を減らす。
|
|
154
|
+
_inherit_backlog_from_latest_session(path, date_str, sessions_dir=SESSIONS_DIR)
|
|
49
155
|
print(f'[Stop] セッションファイルを作成しました: {path}', file=sys.stderr)
|
|
50
156
|
except FileExistsError:
|
|
51
157
|
# /exit による中断等でファイルが空の場合はテンプレートを書き直す(DRY: session_utils へ委譲)
|
|
@@ -65,8 +171,12 @@ def _apply_session_updates(path: str, content: str, message: str = '') -> None:
|
|
|
65
171
|
now = datetime.now(timezone.utc).astimezone().strftime('%Y-%m-%d %H:%M:%S')
|
|
66
172
|
updated = re.sub(r'(- 記録時刻: ).*', rf'\g<1>{now}', content)
|
|
67
173
|
|
|
68
|
-
#
|
|
69
|
-
|
|
174
|
+
# 最終応答を最新メッセージに更新する(既存があれば上書き、なければ追記)。
|
|
175
|
+
# 同一 stop hook 呼び出し内の冪等性は session_stop.py が stop.run を 1 回だけ呼ぶ
|
|
176
|
+
# + stop_hook_active 早期 return (run() 内) で担保されているため、過去セッションの
|
|
177
|
+
# 古い応答は積極的に上書きしてよい。古い `not in updated` ガードは「最初の応答が
|
|
178
|
+
# 一日中残る」問題を引き起こしていた。
|
|
179
|
+
if message:
|
|
70
180
|
single_line = ' '.join(message.split())
|
|
71
181
|
# サロゲート文字など UTF-8 非互換文字を除去(JSON デコード時に生成される場合がある)
|
|
72
182
|
single_line = single_line.encode('utf-8', errors='replace').decode('utf-8')
|
|
@@ -76,11 +186,23 @@ def _apply_session_updates(path: str, content: str, message: str = '') -> None:
|
|
|
76
186
|
# --> をサニタイズして <!-- C3:SESSION:JSON ... --> ブロックを保護する
|
|
77
187
|
truncated = truncated.replace('-->', '-- >')
|
|
78
188
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
189
|
+
# 置換文字列に truncated(LLM 出力由来)を直接埋め込むと \1 等が後方参照として
|
|
190
|
+
# 解釈される。両分岐とも lambda で構造的に防御する [SR-V-001 Info-1]。
|
|
191
|
+
if '- 最終応答:' in updated:
|
|
192
|
+
replacement = f'- 最終応答: {truncated}'
|
|
193
|
+
updated = re.sub(
|
|
194
|
+
r'- 最終応答: [^\n]*',
|
|
195
|
+
lambda _: replacement,
|
|
196
|
+
updated,
|
|
197
|
+
count=1,
|
|
198
|
+
)
|
|
199
|
+
else:
|
|
200
|
+
updated = re.sub(
|
|
201
|
+
r'(- 記録時刻: [^\n]*)',
|
|
202
|
+
lambda m: m.group(0) + f'\n- 最終応答: {truncated}',
|
|
203
|
+
updated,
|
|
204
|
+
count=1,
|
|
205
|
+
)
|
|
84
206
|
|
|
85
207
|
if updated != content:
|
|
86
208
|
dir_ = os.path.dirname(path)
|
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.16.0 (2026-05-24)
|
|
4
|
+
|
|
5
|
+
### 修正
|
|
6
|
+
|
|
7
|
+
- **stop.py: 最終応答が古いまま残るバグを修正**:
|
|
8
|
+
`_apply_session_updates` の `if message and '- 最終応答:' not in updated:`
|
|
9
|
+
ガードにより、1 日に複数 Claude セッションがあると最初のセッションの最終
|
|
10
|
+
応答が一日中残り続けていた。`re.sub` で最新メッセージに上書きする方式に
|
|
11
|
+
変更。同一 stop hook 呼び出し内の冪等性は `session_stop.py` の単一プロセス +
|
|
12
|
+
`stop_hook_active` 早期 return で従来通り担保されている。
|
|
13
|
+
|
|
14
|
+
### 追加
|
|
15
|
+
|
|
16
|
+
- **stop.py: 残タスクの前日自動引き継ぎ機能**:
|
|
17
|
+
新規ヘルパー `_inherit_backlog_from_latest_session` を追加し、
|
|
18
|
+
`ensure_session_file` の新規作成パスで `SESSIONS_DIR` 内の直近過去 `.tmp`
|
|
19
|
+
から `## 残タスク` セクションの `- [ ]` 行のみを抽出して当日ファイルに
|
|
20
|
+
引き継ぐ。既存当日ファイルがある場合 (`FileExistsError` ブランチ) は
|
|
21
|
+
発動せずユーザー編集を尊重する。`init-session` Step 1.5(git log 照合)が
|
|
22
|
+
これまで空ファイルでは何も検出できなかった問題を構造的に解消。
|
|
23
|
+
- **過去ファイル由来の制御文字サニタイズ** [SR-V-001]:
|
|
24
|
+
`_INHERIT_SANITIZE_RE` を導入し、過去ファイルから引き継ぐ `- [ ]` 行に
|
|
25
|
+
含まれる C0/C1 制御文字 (`\x00-\x08` / `\x0b-\x1f` / `\x7f-\x9f`) と
|
|
26
|
+
U+2028 / U+2029 を除去。タブ (`\x09`) と通常スペース (`\x20`) は保持。
|
|
27
|
+
universal newlines による `\r` の `\n` 変換と二層で防御することで、
|
|
28
|
+
過去ファイル改ざんによる端末インジェクションを構造的に防ぐ。
|
|
29
|
+
- **新規ヘルパー `_inherit_backlog_from_latest_session` の `sessions_dir`
|
|
30
|
+
引数**: テスト時にモジュールグローバル `SESSIONS_DIR` を差し替えずに
|
|
31
|
+
動作確認できるよう、`sessions_dir: str | None = None` 引数を追加。
|
|
32
|
+
`ensure_session_file` からは `sessions_dir=SESSIONS_DIR` を明示渡し。
|
|
33
|
+
|
|
34
|
+
### 改善
|
|
35
|
+
|
|
36
|
+
- **`_apply_session_updates` の `re.sub` 置換文字列を lambda 形式に統一**:
|
|
37
|
+
上書き分岐 / 追記分岐の両方で `lambda _: replacement` または
|
|
38
|
+
`lambda m: ...` 形式に統一し、LLM 出力由来の `\1` 等が後方参照として
|
|
39
|
+
解釈されるリスクを構造的に防御。
|
|
40
|
+
- **アトミック書き込みの tempfile suffix を `.writing` に変更**:
|
|
41
|
+
`_inherit_backlog_from_latest_session` 内の一時ファイルが `.tmp`
|
|
42
|
+
フィルタと誤検出される可能性を排除(書き込み途中の一時ファイルを
|
|
43
|
+
`YYYYMMDD.tmp` として誤認することを構造的に防ぐ)。
|
|
44
|
+
|
|
45
|
+
### 回帰防御
|
|
46
|
+
|
|
47
|
+
- `tests/test_stop_additional.py` に新規 10 件のテスト追加:
|
|
48
|
+
- `TestAppendLastMessageOverwrite` (3 件): 最終応答上書き / 他セクション
|
|
49
|
+
保全 / 冪等性
|
|
50
|
+
- `TestInheritBacklogFromLatestSession` (4 件): 引き継ぎ動作 / 過去
|
|
51
|
+
ファイル無し / 既存当日ファイル保護 / 完了済みのみケース
|
|
52
|
+
- `TestInheritBacklogControlCharSanitize` (1 件): 制御文字・ANSI・
|
|
53
|
+
U+2028/U+2029 の除去とタブ・スペース保持
|
|
54
|
+
- `TestInheritBacklogSessionsDirArg` (1 件): `sessions_dir` 引数経路
|
|
55
|
+
- `TestInheritBacklogNewPathOSErrorGuard` (1 件): `new_path` 読み込み
|
|
56
|
+
OSError の伝播防止
|
|
57
|
+
- pytest フル実行: **944 passed** / 4 skipped / 0 regression
|
|
58
|
+
|
|
59
|
+
### 内部
|
|
60
|
+
|
|
61
|
+
- `_inherit_backlog_from_latest_session` の `new_path` 読み込みに
|
|
62
|
+
`try/except OSError: return` を追加。Stop hook プロセスの異常終了を防ぐ。
|
|
63
|
+
- `_INHERIT_SANITIZE_RE` の U+2028 / U+2029 は `chr(0x2028)` + `chr(0x2029)`
|
|
64
|
+
の連結で構築(raw string が `\uXXXX` を解釈しないため、表記揺れを排除)。
|
|
65
|
+
- `tests/test_stop_additional.py`: `from session_utils import extract_section`
|
|
66
|
+
をファイル先頭に集約 / `_setup` 戻り値型ヒントを精緻化。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
3
70
|
## v2.15.2 (2026-05-24)
|
|
4
71
|
|
|
5
72
|
### 改善
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-conductor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.16.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
|