claude-code-conductor 2.71.0__tar.gz → 2.71.1__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.71.0 → claude_code_conductor-2.71.1}/CHANGELOG.md +24 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/PKG-INFO +1 -1
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/__init__.py +1 -1
- claude_code_conductor-2.71.1/src/c3/_terminal.py +118 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_ask.py +11 -3
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/question.py +22 -2
- claude_code_conductor-2.71.1/tests/test_cli_ask.py +793 -0
- claude_code_conductor-2.71.0/src/c3/_terminal.py +0 -64
- claude_code_conductor-2.71.0/tests/test_cli_ask.py +0 -349
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/.gitignore +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/design-critic.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/agents/wt_tester.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/breaking-changes.txt +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/deletions.txt +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/autonomous-mode-onboarding.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/config-policy.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/nul-boundary.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/platform-adapters.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/_hook_utils.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/patterns_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/permission_handler.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/permission_handler_toast.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/recall_autorebuild.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/report_contract_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/report_path_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/session_mode_watch.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/tier_autoapply.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/tier_gap_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/permission_rules.json +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/rules/judgment-principles.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/settings.json +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/autonomous-mode/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/autonomous-mode/scripts/mode_line.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/brainstorm/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/codex-review/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/c3-omission-declaration.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/reachability-map.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/record-protocol.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/scripts/detect_execution_verification.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/init-session/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/init-session/scripts/session_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/start/SKILL.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/skills/start/scripts/archive_reports.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/.gitignore +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/ARCHITECTURE.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSES/numpy-LICENSE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/README.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/hatch_build.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/pyproject.toml +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/_db_params.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/adapters.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_metrics.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_run.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/db.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/gitutil.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrate.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/001_initial.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/003_tier_cost.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/004_agent_outcomes.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/006_review_decisions_severity.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/007_review_decisions_resolution.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/008_drop_agent_runs.sql +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/README.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/migrations/__init__.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/pricing.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/refgraph.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/src/c3/usage_ingester.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/__init__.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/_pre_compact_helpers.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/conftest.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/fixtures/usage/README.md +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/fixtures/usage/mainline.jsonl +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_detect_execution_verification.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_hook_utils.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_permission_handler.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_permission_handler_toast.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_recall_autorebuild.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_record_agent_outcome.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_report_path_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_settings_tier_autoapply_registration.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_tier_autoapply.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_tier_gap_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/hooks/test_tier_security_fixes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/_skill_helpers.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_c3_omission_declaration.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_e0_verification_exit.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_init_session_no_task_type.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_marker_compliance.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_parallel_agents_skill_tier.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_reachability_map.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_session_backlog_reconciliation.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_session_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_start_skill_new_flow.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_adapters.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_archive_reports.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_audit_review_decisions.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_check_deletions.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_ci_workflows.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_claude_gitignore.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_doctor.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_doctor_launcher.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_metrics.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_run.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_update_breaking_changes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_cli_update_deletions.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_db.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_db_connect_lint.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_extract_breaking_changes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_gitutil.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_hooks_stdin_idiom.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_init_only_patterns.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_migrate.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_mode_line.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_no_bare_python_launcher.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_no_passonly_tests.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_nul_boundary_lint.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_patterns_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_pricing.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_refgraph.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_refgraph_query.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_refgraph_structural.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_report_contract_check.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_scripts_src_bootstrap.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_scripts_stdout_encoding.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_session_mode_watch.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_settings_hooks_registration.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_start_skill_archive_contract.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_stop_agent_memory_warn.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_usage_ingester.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_worktree_guard.py +0 -0
- {claude_code_conductor-2.71.0 → claude_code_conductor-2.71.1}/tests/test_wt_agent_sync.py +0 -0
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.71.1] - 2026-08-14
|
|
4
|
+
|
|
5
|
+
### 修正
|
|
6
|
+
|
|
7
|
+
- **`c3 ask` の Windows 非対話判定が機能せず無限ハングする欠陥を修正した**(v2.71.0
|
|
8
|
+
「既知の問題」の解消)。`sys.stdin.isatty()` が Windows で stdin を NUL / `/dev/null` へ
|
|
9
|
+
リダイレクトした場合にも True を誤返却し、`--response` 未指定で exit 1 にならず
|
|
10
|
+
`msvcrt.getwch()`(実コンソール直読み)で無限ハングしていた。判定を
|
|
11
|
+
`stdin_is_interactive_console()`(Windows は GetConsoleMode で実コンソール接続を判定・
|
|
12
|
+
POSIX は従来どおり `isatty()`)へ置換し、入口ゲートと対話パス直前の二重ゲートを
|
|
13
|
+
同一判定へ統一した
|
|
14
|
+
- 判定ヘルパーを共有モジュール `src/c3/_terminal.py` へ移設し、関数全体を一箇所集約で
|
|
15
|
+
fail-closed 化した(想定外例外でも非対話扱い=exit 1 契約を維持・KeyboardInterrupt /
|
|
16
|
+
SystemExit は伝播。`question.py` 側は re-export でシーム維持)
|
|
17
|
+
- `_read_key` の POSIX 分岐に空読み EOF ガードを追加した(EOF 時のビジーループを解消し
|
|
18
|
+
既存の exit 1 経路へ接続)
|
|
19
|
+
- `docs/cli-reference.md` の v2.71 既知問題注記を修正後の実挙動へ更新した
|
|
20
|
+
|
|
21
|
+
### 内部
|
|
22
|
+
|
|
23
|
+
- `tests/test_cli_ask.py` に回帰・凍結テスト計 17 件を追加した(修正前状態での赤化実証・
|
|
24
|
+
内部依存注入による fail-closed 凍結・Windows 限定 subprocess+timeout 統合テストを含む。
|
|
25
|
+
フルスイート 3322 緑・CI 全緑 run 31755508514)
|
|
26
|
+
|
|
3
27
|
## [2.71.0] - 2026-08-14
|
|
4
28
|
|
|
5
29
|
### 追加
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: claude-code-conductor
|
|
3
|
-
Version: 2.71.
|
|
3
|
+
Version: 2.71.1
|
|
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
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Shared terminal helpers for c3 CLI subcommands.
|
|
2
|
+
|
|
3
|
+
Used by cli_doctor.py, cli_tier.py, cli_ask.py, question.py, and future
|
|
4
|
+
cli_*.py to keep terminal-facing logic in one place:
|
|
5
|
+
|
|
6
|
+
- ``supports_color`` / ``strip_ansi`` / ``sanitize_terminal_text``: ANSI
|
|
7
|
+
color support detection, escape-sequence stripping, and sanitization of
|
|
8
|
+
untrusted text before printing.
|
|
9
|
+
- ``stdin_is_interactive_console``: console-attachment detection for stdin
|
|
10
|
+
(whether an interactive console is really attached, as opposed to a NUL /
|
|
11
|
+
pipe / file redirection).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# CSI sequences with final byte 'm' (color / SGR). Other escape sequences
|
|
22
|
+
# (e.g. \033c reset, OSC \033]0;...\007 title) are not handled by _strip_ansi
|
|
23
|
+
# and would skew column-width calculations if they appeared in cell text.
|
|
24
|
+
_CSI_M_RE = re.compile(r"\033\[[0-9;]*m")
|
|
25
|
+
|
|
26
|
+
# Control characters disallowed when printing untrusted text to the terminal.
|
|
27
|
+
# Allow newline (\n), tab (\t), carriage return (\r) but strip any other
|
|
28
|
+
# C0 control or escape character (\x1b) so that ANSI/title-injection cannot
|
|
29
|
+
# happen via DB-stored values such as ``current_step`` / ``error_message``.
|
|
30
|
+
# Also strip the Unicode line/paragraph separators U+2028 / U+2029 so they
|
|
31
|
+
# match the init-session SR L-2 sanitization spec (removes U+2028 / U+2029).
|
|
32
|
+
# NEL (U+0085) is intentionally NOT included per that spec.
|
|
33
|
+
_DISALLOWED_CONTROL_RE = re.compile("[\x00-\x08\x0b\x0c\x0e-\x1f\x7f" + chr(0x2028) + chr(0x2029) + "]")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def supports_color() -> bool:
|
|
37
|
+
"""Return True if stdout supports ANSI color sequences.
|
|
38
|
+
|
|
39
|
+
Honors the NO_COLOR environment variable (https://no-color.org/) and
|
|
40
|
+
requires stdout to be a TTY.
|
|
41
|
+
"""
|
|
42
|
+
if os.environ.get("NO_COLOR"):
|
|
43
|
+
return False
|
|
44
|
+
if not sys.stdout.isatty():
|
|
45
|
+
return False
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def strip_ansi(s: str) -> str:
|
|
50
|
+
"""Remove ANSI CSI 'm' (SGR / color) sequences for visible-width calc.
|
|
51
|
+
|
|
52
|
+
Note: handles only ``\\033[...m`` style sequences. Other escape sequences
|
|
53
|
+
such as cursor movement (``\\033[H``), screen clear (``\\033[2J``), or
|
|
54
|
+
OSC title-set are intentionally not stripped here because the cells we
|
|
55
|
+
measure should never contain them.
|
|
56
|
+
"""
|
|
57
|
+
return _CSI_M_RE.sub("", s)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def sanitize_terminal_text(s: str) -> str:
|
|
61
|
+
"""Strip control / escape characters from untrusted text before printing.
|
|
62
|
+
|
|
63
|
+
Used for DB-sourced strings (``current_step`` / ``error_message``) so
|
|
64
|
+
they cannot inject ANSI escape sequences (title, cursor, screen clear)
|
|
65
|
+
into the terminal. Newlines / tabs / carriage returns are preserved.
|
|
66
|
+
The Unicode line/paragraph separators U+2028 / U+2029 are also stripped
|
|
67
|
+
(init-session SR L-2 sanitization spec); NEL (U+0085) is out of scope.
|
|
68
|
+
"""
|
|
69
|
+
if not s:
|
|
70
|
+
return s
|
|
71
|
+
return _DISALLOWED_CONTROL_RE.sub("", s)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def stdin_is_interactive_console() -> bool:
|
|
75
|
+
"""Return True only when stdin is attached to a real interactive console.
|
|
76
|
+
|
|
77
|
+
Windows の CRT ``_isatty()``(``sys.stdin.isatty()`` の内部実装)は対象ハンドルが
|
|
78
|
+
``FILE_TYPE_CHAR`` かどうかしか見ておらず、NUL デバイス(``subprocess.DEVNULL`` /
|
|
79
|
+
``NUL`` リダイレクト)もコンソールと同じ ``FILE_TYPE_CHAR`` に分類されるため
|
|
80
|
+
誤って True を返す(実測: debug-analysis-20260814-011032.md)。
|
|
81
|
+
Windows では ``GetConsoleMode``(実コンソールハンドルに対してのみ成功する
|
|
82
|
+
Win32 API)で実際のコンソール接続を確認し、NUL・パイプ・ファイルいずれの
|
|
83
|
+
リダイレクトも False として扱う。POSIX は ``isatty()`` が ``/dev/null`` に
|
|
84
|
+
対して標準どおり正しく False を返すためそのまま使う。
|
|
85
|
+
|
|
86
|
+
関数全体を ``except Exception`` で包み、内部でどの分岐がどの例外型を投げても
|
|
87
|
+
送出せず False を返す (fail-closed)。POSIX 分岐の ``sys.stdin.isatty()`` は
|
|
88
|
+
``sys.stdin`` が None のケース (pythonw.exe / PyInstaller --windowed など) で
|
|
89
|
+
``AttributeError`` を投げうるが、これを呼び出し元へ伝播させると
|
|
90
|
+
``c3 ask`` の「exit 1」契約が破れる (SR-R-001 / CR-E-001)。呼び出し位置ごとに
|
|
91
|
+
try/except を足すのではなく、ここ一箇所へ集約して将来の呼び出し箇所追加にも
|
|
92
|
+
自動的に効かせる。``KeyboardInterrupt`` / ``SystemExit`` は ``BaseException``
|
|
93
|
+
直属で ``Exception`` を継承しないため握り潰さない (Ctrl-C は従来どおり伝播)。
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
if os.name == "nt":
|
|
97
|
+
return _windows_console_attached()
|
|
98
|
+
return sys.stdin.isatty()
|
|
99
|
+
except Exception:
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _windows_console_attached() -> bool:
|
|
104
|
+
try:
|
|
105
|
+
import ctypes
|
|
106
|
+
import msvcrt
|
|
107
|
+
from ctypes import wintypes
|
|
108
|
+
|
|
109
|
+
handle = msvcrt.get_osfhandle(0)
|
|
110
|
+
kernel32 = ctypes.windll.kernel32
|
|
111
|
+
kernel32.GetConsoleMode.argtypes = [wintypes.HANDLE, ctypes.POINTER(wintypes.DWORD)]
|
|
112
|
+
kernel32.GetConsoleMode.restype = wintypes.BOOL
|
|
113
|
+
mode = wintypes.DWORD()
|
|
114
|
+
return bool(kernel32.GetConsoleMode(wintypes.HANDLE(handle), ctypes.byref(mode)))
|
|
115
|
+
except Exception:
|
|
116
|
+
# 判定不能ならすべて非対話扱いに倒す (fail-closed)。answer_questions() 経由の
|
|
117
|
+
# 呼び出し位置も含め、想定外の例外型で対話ゲートを突破させない。
|
|
118
|
+
return False
|
|
@@ -7,6 +7,7 @@ import json
|
|
|
7
7
|
import sys
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
+
from c3._terminal import stdin_is_interactive_console
|
|
10
11
|
from c3.question import answer_questions, load_questions
|
|
11
12
|
|
|
12
13
|
|
|
@@ -47,9 +48,16 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def handle(args: argparse.Namespace) -> int:
|
|
50
|
-
if args.response is None
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
if args.response is None:
|
|
52
|
+
# 判定関数が想定外の例外を出しても traceback で落とさず「非対話」へ倒す
|
|
53
|
+
# (fail-closed)。--response 未指定時の exit 1 契約を例外型に依存させない。
|
|
54
|
+
try:
|
|
55
|
+
interactive = stdin_is_interactive_console()
|
|
56
|
+
except Exception:
|
|
57
|
+
interactive = False
|
|
58
|
+
if not interactive:
|
|
59
|
+
print("c3 ask: --response is required in non-interactive mode", file=sys.stderr)
|
|
60
|
+
return 1
|
|
53
61
|
|
|
54
62
|
try:
|
|
55
63
|
if args.file is not None:
|
|
@@ -13,6 +13,12 @@ from dataclasses import dataclass
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
|
+
# stdin_is_interactive_console() は共有ターミナルヘルパー _terminal.py が正本
|
|
17
|
+
# (CR-R-003)。ここでの import は question.py 内部の呼び出し元 (answer_questions /
|
|
18
|
+
# _raw_keyboard_supported) が使うと同時に、``question.stdin_is_interactive_console``
|
|
19
|
+
# という従来の参照名を後方互換で維持する re-export を兼ねる。
|
|
20
|
+
from c3._terminal import stdin_is_interactive_console
|
|
21
|
+
|
|
16
22
|
|
|
17
23
|
@dataclass(frozen=True)
|
|
18
24
|
class Option:
|
|
@@ -63,7 +69,7 @@ def answer_questions(
|
|
|
63
69
|
if current_response is not None:
|
|
64
70
|
selected = _select_from_response(question, current_response)
|
|
65
71
|
else:
|
|
66
|
-
use_interactive =
|
|
72
|
+
use_interactive = stdin_is_interactive_console() if interactive is None else interactive
|
|
67
73
|
selected = _select_interactively(question) if use_interactive else _select_default(question)
|
|
68
74
|
answers.append(_answer_payload(question, selected))
|
|
69
75
|
return {"answers": answers}
|
|
@@ -383,7 +389,16 @@ def _clear_screen() -> None:
|
|
|
383
389
|
|
|
384
390
|
|
|
385
391
|
def _raw_keyboard_supported() -> bool:
|
|
386
|
-
|
|
392
|
+
# OS が raw keyboard API を持つかではなく、今この stdin に実コンソールが
|
|
393
|
+
# 接続されているかを見る。旧実装(os.name in ("nt", "posix"))は事実上
|
|
394
|
+
# 常に True を返し、NUL/パイプ/ファイルへのリダイレクト時でも
|
|
395
|
+
# _select_with_line_input() の安全網(input() → EOFError)を恒久的に
|
|
396
|
+
# 迂回させ msvcrt.getwch() の無限ブロックを招いていた
|
|
397
|
+
# (debug-analysis-20260814-011032.md 欠陥B)。
|
|
398
|
+
# answer_questions() の外側ゲートと同じ判定をここでも呼ぶのは、interactive=True を
|
|
399
|
+
# 明示指定して外側ゲートを迂回する呼び出し元にも安全網を効かせるための意図的な
|
|
400
|
+
# 再検証であり、単純な重複ではない(削除・簡略化しないこと)。
|
|
401
|
+
return stdin_is_interactive_console()
|
|
387
402
|
|
|
388
403
|
|
|
389
404
|
def _read_key() -> str:
|
|
@@ -410,6 +425,11 @@ def _read_key() -> str:
|
|
|
410
425
|
try:
|
|
411
426
|
tty.setraw(fd)
|
|
412
427
|
ch = sys.stdin.read(1)
|
|
428
|
+
if ch == "":
|
|
429
|
+
# EOF(read が空文字列)。空文字列を返すと _select_interactively() の
|
|
430
|
+
# ループが再描画しながら回り続け CPU ビジーループになるため、
|
|
431
|
+
# EOFError を送出して呼び出し元(cli_ask.handle の except EOFError)へ委ねる。
|
|
432
|
+
raise EOFError("stdin reached EOF while reading a key")
|
|
413
433
|
if ch == "\x1b":
|
|
414
434
|
nxt = sys.stdin.read(2)
|
|
415
435
|
return {"[A": "up", "[B": "down", "[C": "right", "[D": "left"}.get(nxt, "escape")
|